Socket之UDP(二)

本文介绍了UDP(User Datagram Protocol)的基础知识,包括其作为非连接协议的特性,最大数据包长度,核心API如DatagramSocket和DatagramPacket的使用方法,以及UDP在单播、广播和多播中的应用。此外,还提供了局域网搜索的UDP案例操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. UDP是什么?

  • 英语:User Datagram Protocal ,缩写为UDP
  • 一种用户报协议,有称为用户数据报文协议
  • 是一个简单的面向数据报传输层协议,正式规范为RFC 768
  • 用户数据协议、非连接协议

2、UDP能做什么?

  • DNS、TFTP、SNMP
  • 视频、音频、普通数据(无关紧要的数据)

    

3、UDP包中最大的长度

  • 16位>2字节存储长度信息。
  • 2^16-1=64k-1=65536-1=65535。
  • 自身协议占用:32+32位=64位=8字节。
  • 65535-8=65507byte

4、UDP核心API 

  1. DatagramSocket
  • 用于接收与发送UDP的类。
  • 负责发送某一个UDP包,或者接收UDP包。
  • 不同于TCP、UDP并没有合并到Socket API中。
  •  DatagramSocket()创建简单实例,不指定端口与ip。
  •  DatagramSocket(int port)创建监听固定端口的实例。
  •  DatagramSocket(int port,InetAddress localAddr)创建固定端口指定ip的实例。
  • receive(DatagramPacket d):接收
  • send(DatagramPack d): 发送
  • setSoTimeout(int timeout): 设置超时、毫秒

     2. DatagramPacket

  • 用于报文处理。
  • 将byte数组、目标地址、目标端口等数据包装成报文或者将报文拆卸成byte数组。
  • 是UDP的发送实体,也是接收实体
  • DatagramPacket(byte[] buf,int offset,int length、InetAddress address,int port).
  • DatagramPacket(byte[] buf,int offset,int length、SocketAddress address)
  • setData(byte[] buf ,int offset,int length)
  • setData(byte[] buf)
  • setLength(int length)
  • getData()、getIffset()、getLength()
  • setAddress(InetAddress iddrr)、setPort(int port)
  • getAddress() 、getPort()
  • setSocketAddress(SocketAddress address)
  • getSocketAddress()

 5、UDP单播、广播、多播

                                   

 为受限  广播地址:255.255.255.25

6、案例操作-局域网搜索案例

  •   UDP接收消息并回送功能实现
  •  UDP 局域网广播发送实现
  •  UDP局域网回送消息实现
package udp;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

/** @author cs udp 提供者 用于提供服务 */
public class UdpProvider {

  public static void main(String[] args) throws Exception {
    //
    System.out.println("UDPProvider Start.. ");
    // 作为接收者 指定一个端口用于数据接收
    DatagramSocket ds = new DatagramSocket(20000);
    // 构建接收实体
    final byte[] buf = new byte[512];
    DatagramPacket recivePack = new DatagramPacket(buf, buf.length);

    // 接收、
    ds.receive(recivePack);

    // 打印接收到的信息与发送者信息
    // 发送者的ip地址
    String ip = recivePack.getAddress().getHostAddress();
    int port = recivePack.getPort();
    int dataLength = recivePack.getLength();

    String data = new String(recivePack.getData(), 0, dataLength);

    System.out.println("UDPProvider receive form ip:" + ip + "\tport:" + port + "\t" + data);

    // 构建一份回送数据

    String responseData = "Recive data with len:" + dataLength;
    byte[] responseDataBytes = responseData.getBytes();
    // 直接根据发送者构建一份回送数据
    DatagramPacket reponsePacket =
        new DatagramPacket(
            responseDataBytes,
            responseDataBytes.length,
            recivePack.getAddress(),
            recivePack.getPort());
    ds.send(reponsePacket);
    // 完成
    System.out.println("UDPProvider finished");
    ds.close();
  }
}
package udp;

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

/** udp 搜索者 用于搜素服务支持方 */
public class UdpSeacher {

  public static void main(String[] args) throws Exception {
    //
    System.out.println("UdpSeacher Start.. ");
    // 作为搜索方 让系统直接分配
    DatagramSocket ds = new DatagramSocket();

    // 构建一份回送数据

    String requestData = "hello world:";
    byte[] requestDataBytes = requestData.getBytes();
    // 直接根据发送者构建一份回送数据
    DatagramPacket requestPacket = new DatagramPacket(requestDataBytes, requestDataBytes.length);
    requestPacket.setAddress(InetAddress.getLocalHost());
    requestPacket.setPort(20000);

    // 发送
    ds.send(requestPacket);

    // 构建接收实体
    final byte[] buf = new byte[512];
    DatagramPacket recivePack = new DatagramPacket(buf, buf.length);

    // 接收
    ds.receive(recivePack);
    // 打印接收到的信息与发送者信息
    // 发送者的ip地址
    String ip = recivePack.getAddress().getHostAddress();
    int port = recivePack.getPort();
    int dataLength = recivePack.getLength();

    String data = new String(recivePack.getData(), 0, dataLength);

    System.out.println("UdpSeacher receive form ip:" + ip + "\tport:" + port + "\t" + data);

    // 完成
    System.out.println("UdpSeacher finished");
    ds.close();
  }
}

二、

package udp1;

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 udp1;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.UUID;

/** @author cs udp 提供者 用于提供服务 */
public class UdpProvider {

  public static void main(String[] args) throws Exception {

    // 生成一份唯一标识
    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 Start.. ");
      try {
        // 监听20000端口
        ds = new DatagramSocket(20000);
        while (!done) {

          // 构建接收实体
          final byte[] buf = new byte[512];
          DatagramPacket recivePack = new DatagramPacket(buf, buf.length);

          // 接收、
          ds.receive(recivePack);

          // 打印接收到的信息与发送者信息
          // 发送者的ip地址
          String ip = recivePack.getAddress().getHostAddress();
          int port = recivePack.getPort();
          int dataLength = recivePack.getLength();

          String data = new String(recivePack.getData(), 0, dataLength);

          System.out.println("UDPProvider receive form ip:" + ip + "\tport:" + port + "\t" + data);

          // 解析我们的端口号
          int reponsePort = MessageCreator.parsePort(data);

          if (reponsePort != -1) {
            // 构建一份回送数据
            String responseData = MessageCreator.BuildWithSn(sn);
            byte[] responseDataBytes = responseData.getBytes();

            // 直接根据发送者构建一份回送数据
            DatagramPacket reponsePacket =
                new DatagramPacket(
                    responseDataBytes,
                    responseDataBytes.length,
                    recivePack.getAddress(),
                    reponsePort);
            ds.send(reponsePacket);
          }
        }
      } catch (Exception e) {

      } finally {
        close();
      }
      // 完成
      System.out.println("UDPProvider finished");
    }

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

    void exit() {

      done = true;
      close();
    }
  }
}
package udp1;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/** udp 搜索者 用于搜素服务支持方 */
public class UdpSeacher {

  private static final int LISTEN_PORT = 30000;

  public static void main(String[] args) throws Exception {
    // 完成
    System.out.println("UDPSearch start");
    Listenner listenner = listen();
    sendBroadcast();

    // 读取任意键盘信息后可以退出
    System.in.read();
    // 拿到设备信息
    List<Device> devices = listenner.getDevicesAndClose();

    for (Device device : devices) {
      System.out.println("device" + device.toString());
    }
    // 完成
    System.out.println("UDPSearch Finshed");
  }

  private static Listenner listen() throws Exception {

    System.out.println("UDPSearch start  Listenner ");
    CountDownLatch countDownLatch = new CountDownLatch(1);
    Listenner listenner = new Listenner(LISTEN_PORT, countDownLatch);
    listenner.start();

    countDownLatch.await();

    return listenner;
  }

  private static void sendBroadcast() throws Exception {

    System.out.println("UdpSeacher  senBroadcast Start.. ");

    // 作为搜索方 让系统直接分配
    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();

    // 构建接收实体
    final byte[] buf = new byte[512];
    DatagramPacket recivePack = new DatagramPacket(buf, buf.length);

    // 完成
    System.out.println("UdpSeacher  senBroadcast finished");
    ds.close();
  }

  private static class Device {

    final int port;

    final String ip;

    final String sn;

    public 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 Listenner extends Thread {

    private int listenport;

    private CountDownLatch countDownLatch;

    private final List<Device> devices = new ArrayList<>();

    private boolean done = false;

    private DatagramSocket datagramSocket = null;

    public Listenner(int listenport, CountDownLatch countDownLatch) {

      super();
      this.listenport = listenport;
      this.countDownLatch = countDownLatch;
    }

    public Listenner() {
      super();
    }

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

      // 通知已启动
      countDownLatch.countDown();

      try {
        datagramSocket = new DatagramSocket(listenport);

        while (!done) {

          // 构建接收实体
          final byte[] buf = new byte[512];
          DatagramPacket recivePack = new DatagramPacket(buf, buf.length);

          // 接收、
          datagramSocket.receive(recivePack);

          // 打印接收到的信息与发送者信息
          // 发送者的ip地址
          String ip = recivePack.getAddress().getHostAddress();
          int port = recivePack.getPort();
          int dataLength = recivePack.getLength();

          String data = new String(recivePack.getData(), 0, dataLength);

          System.out.println("UDPSearch receive form ip:" + ip + "\tport:" + port + "\t" + data);

          String sn = MessageCreator.parseSn(data);

          if (sn != null) {
            Device device = new Device(port, ip, sn);

            devices.add(device);
          }
        }

      } catch (Exception e) {

      } finally {

        close();
      }
      System.out.println("UDPSearch lisen end");
    }

    private void close() {

      if (datagramSocket != null) {
        datagramSocket.close();
        datagramSocket = null;
      }
    }

    List<Device> getDevicesAndClose() {

      done = true;
      close();
      return devices;
    }
  }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值