【Socket網絡編程進階與實戰】------- Socket UDP快速入門

前言

Socket UDP快速入門,demo實戰


UDP

在這裏插入圖片描述

爲什麼不可靠

在這裏插入圖片描述

能做什麼

在這裏插入圖片描述

UDP包最大長度

在這裏插入圖片描述

核心API

API-DatagramSocket

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

API-DatagramPacket

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

UDP 單播、廣播、多播

在這裏插入圖片描述

  • IP地址類別
    在這裏插入圖片描述
  • 廣播地址
    在這裏插入圖片描述
    在這裏插入圖片描述
  • 廣播地址運算
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述
  • 廣播通信問題
    在這裏插入圖片描述

案例實操-局域網搜索案例

  • UDP接收消息並回送功能實現
  • UDP局域網廣播發送實現
  • UDP局域網回送消息實現
package com.zcw.demo;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

/**
 * @ClassName : UDPProvider
 * @Description :UDP提供者,用於提供服務
 * @Author : Zhaocunwei
 * @Date: 2020-07-07 14:09
 */
public class UDPProvider {
    public static void main(String[] args) throws IOException {
        System.out.println("UDPProvider  Started.");
        //作爲接收者,指定一個端口用於數據接收
        DatagramSocket ds = new DatagramSocket(20000);
        //構建接收實體
        final byte[] buf = new byte[512];
        DatagramPacket receivePack = new DatagramPacket(buf,buf.length);

        //接收
        ds.receive(receivePack);
        //打印接收到的信息與發送者的信息
        //發送者的IP地址
        String ip = receivePack.getAddress().getHostAddress();
        int port = receivePack.getPort();
        int dataLen = receivePack.getLength();
        String data = new String(receivePack.getData(),0,dataLen);
        System.out.println("UDPProvider receive form ip:"+ip
          +"\tport:"+port+"\tdata:"+data);

        //構建一份回送數據
        String responseData = "Receive data winth len:"+dataLen;
        byte[] responseDataBytes = responseData.getBytes();
        //直接根據發送者構建一份回送信息
        DatagramPacket responsePacket = new DatagramPacket(responseDataBytes,
                responseDataBytes.length,
                receivePack.getAddress(),
                receivePack.getPort());
        ds.send(responsePacket);
        //完成
        System.out.println("UDPProvider  Finished.");
        ds.close();
    }
}



package com.zcw.demo;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * @ClassName : UDPSearcher
 * @Description : UDP 搜索,用於搜索服務支持方
 * @Author : Zhaocunwei
 * @Date: 2020-07-07 14:09
 */
public class UDPSearcher {
    public static void main(String[] args) throws IOException {
        System.out.println("UDPSearcher  Started.");
        //作爲搜索方,讓系統自動分配端口
        DatagramSocket ds = new DatagramSocket();

        //構建一份回送數據
        String requestData = "HelloWord:";
        byte[] requestDataBytes = requestData.getBytes();
        //直接根據發送者構建一份回送信息
        DatagramPacket requestPacket = new DatagramPacket(requestDataBytes,
                requestDataBytes.length);
        //本機端口20000
        requestPacket.setAddress(InetAddress.getLocalHost());
        requestPacket.setPort(20000);
        ds.send(requestPacket);


        //構建接收實體
        final byte[] buf = new byte[512];
        DatagramPacket receivePack = new DatagramPacket(buf,buf.length);

        //接收
        ds.receive(receivePack);
        //打印接收到的信息與發送者的信息
        //發送者的IP地址
        String ip = receivePack.getAddress().getHostAddress();
        int port = receivePack.getPort();
        int dataLen = receivePack.getLength();
        String data = new String(receivePack.getData(),0,dataLen);
        System.out.println("UDPSearcher receive form ip:"+ip
                +"\tport:"+port+"\tdata:"+data);


        //完成
        System.out.println("UDPSearcher  Finished.");
        ds.close();
    }
}

  • 測試:
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述

優化上面Demo

  • 創建消息創建者
package com.zcw.demo;

/**
 * @ClassName : MessageCreator
 * @Description :發送消息
 * @Author : Zhaocunwei
 * @Date: 2020-07-07 14:44
 */
public class MessageCreator {
    private static final String SN_HEADER="收到暗號,我是(SN):";
    private static final String PORT_HEADER="這是暗號,請回端口(Port):";

    public static String buildWithPort(int port){
        return PORT_HEADER +port;
    }
  public static int parsePort(String data){
        if(data.startsWith(PORT_HEADER)){
            return Integer.parseInt(data.substring(PORT_HEADER.length()));
        }
        return -1;
  }
  public static String buildWithSn(String sn){
        return SN_HEADER+sn;
  }
  public static String parseSn(String data){
        if(data.startsWith(SN_HEADER)){
            return data.substring(SN_HEADER.length());
        }
        return null;
  }
}


  • 修改內容提供者
package com.zcw.demo;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.UUID;

/**
 * @ClassName : UDPProvider
 * @Description :UDP提供者,用於提供服務
 * @Author : Zhaocunwei
 * @Date: 2020-07-07 14:09
 */
public class UDPProvider {
    public static void main(String[] args) throws IOException {
        //生成一份唯一標識
        String sn = UUID.randomUUID().toString();
        Provider provider = new Provider(sn);
        provider.start();


        //讀取任意鍵盤信息後可以退出
        System.in.read();
        provider.exit();
    }

    private static class Provider extends Thread {
        private final String sn;
        private boolean done = false;
        private DatagramSocket ds = null;

        public Provider(String sn) {
            super();
            this.sn = sn;
        }

        @Override
        public void run() {
            super.run();

            System.out.println("UDPProvider  Started.");
            try {
                //構造一個監聽
                ds = new DatagramSocket(20000);
                while (!done) {

                    //構建接收實體
                    final byte[] buf = new byte[512];
                    DatagramPacket receivePack = new DatagramPacket(buf, buf.length);

                    //接收
                    ds.receive(receivePack);
                    //打印接收到的信息與發送者的信息
                    //發送者的IP地址
                    String ip = receivePack.getAddress().getHostAddress();
                    int port = receivePack.getPort();
                    int dataLen = receivePack.getLength();
                    String data = new String(receivePack.getData(), 0, dataLen);
                    System.out.println("UDPProvider receive form ip:" + ip
                            + "\tport:" + port + "\tdata:" + data);

                    //解析端口號
                    int responsePort = MessageCreator.parsePort(data);
                    if (responsePort != -1) {

                        //構建一份回送數據
                        String responseData = MessageCreator.buildWithSn(sn);
                        byte[] responseDataBytes = responseData.getBytes();
                        //直接根據發送者構建一份回送信息
                        DatagramPacket responsePacket = new DatagramPacket(responseDataBytes,
                                responseDataBytes.length,
                                receivePack.getAddress(),
                                responsePort);
                        ds.send(responsePacket);
                    }
                }
            } catch (Exception ignored) {
            } finally {
                close();
            }
            //完成
            System.out.println("UDPProvider  Finished.");
        }

        private void close() {
            if (ds != null) {
                ds.close();
                ds = null;
            }
        }

        /**
         * 提供結束方法
         */
        void exit() {
            done = true;
            close();
        }
    }
}


  • 修改我們的數據搜索者

package com.zcw.demo;

import java.io.IOException;
import java.net.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * @ClassName : UDPSearcher
 * @Description : UDP 搜索,用於搜索服務支持方
 * @Author : Zhaocunwei
 * @Date: 2020-07-07 14:09
 */
public class UDPSearcher {
    private static final int LISTEN_PORT=30000;

    public static void main(String[] args) throws IOException, InterruptedException {
        System.out.println("UDPSearcher  Started.");

        Listener listen = listen();
        sendBroadcast();

        //讀取任意鍵盤信息後可以退出
        System.in.read();
        List<Device> devices = listen.getDevicesAndClose();
        for (Device device :devices){
            System.out.println("Device:"+device.toString());

        }
        //完成
        System.out.println("UDPSearcher  Finished.");
    }

    private static Listener listen() throws InterruptedException {
        System.out.println("UDPSearcher  start listen.");
        CountDownLatch countDownLatch = new CountDownLatch(1);
        Listener listener = new Listener(LISTEN_PORT,countDownLatch);
        listener.start();
        countDownLatch.await();
        return listener;
    }

    private static void sendBroadcast() throws IOException {
        System.out.println("UDPSearcher sendBroadcast  Started.");
        //作爲搜索方,讓系統自動分配端口
        DatagramSocket ds = new DatagramSocket();

        //構建一份回送數據
        String requestData = MessageCreator.buildWithPort(LISTEN_PORT);
        byte[] requestDataBytes = requestData.getBytes();
        //直接根據發送者構建一份回送信息
        DatagramPacket requestPacket = new DatagramPacket(requestDataBytes,
                requestDataBytes.length);

        //20000端口,廣播地址
        requestPacket.setAddress(InetAddress.getByName("255.255.255.255"));
        requestPacket.setPort(20000);
        ds.send(requestPacket);
        ds.close();

        //完成
        System.out.println("UDPSearcher  sendBroadcast Finished.");
    }
    private static class Device{
        final int port;
        final String ip;
        final String sn;

        private Device(int port, String ip, String sn) {
            this.port = port;
            this.ip = ip;
            this.sn = sn;
        }

        @Override
        public String toString() {
            return "Device{" +
                    "port=" + port +
                    ", ip='" + ip + '\'' +
                    ", sn='" + sn + '\'' +
                    '}';
        }
    }
    /**
     * 實現監聽類
     */
    private static class Listener extends Thread{
        private final int listenPort;
        private final CountDownLatch countDownLatch;
        private final List<Device> devices = new ArrayList<Device>();
        private boolean done = false;
        private DatagramSocket ds =null;

        public Listener(int listenPort, CountDownLatch countDownLatch){
            super();
            this.listenPort = listenPort;
            this.countDownLatch = countDownLatch;
        }
        @Override
        public void run(){
            super.run();
            //通知已啓動
            countDownLatch.countDown();
            try{
                //監聽回送端口
              ds = new DatagramSocket(listenPort);
               while(!done){
                   //構建接收實體
                   final byte[] buf = new byte[512];
                   DatagramPacket receivePack = new DatagramPacket(buf,buf.length);

                   //接收
                   ds.receive(receivePack);
                   //打印接收到的信息與發送者的信息
                   //發送者的IP地址
                   String ip = receivePack.getAddress().getHostAddress();
                   int port = receivePack.getPort();
                   int dataLen = receivePack.getLength();
                   String data = new String(receivePack.getData(),0,dataLen);
                   System.out.println("UDPSearcher receive form ip:"+ip
                           +"\tport:"+port+"\tdata:"+data);

                   String sn = MessageCreator.parseSn(data);
                    if(sn!=null){
                        Device device = new Device(port,ip,sn);
                        devices.add(device);
                    }
               }
            }catch(Exception ignored){

            }finally {
                close();
            }
            System.out.println("UDPSearcher listener finished");
        }
        private void close(){
            if(ds!=null){
                ds.close();
                ds=null;
            }
        }
        List<Device> getDevicesAndClose(){
            done=true;
            close();
            return devices;
        }
    }
}


  • 測試:
    在這裏插入圖片描述
    在這裏插入圖片描述
    在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章