Skip to content

Java IO - 06 UDP通信

本文主要介绍如何在Java中进行UDP通信,涉及的类包括DatagramSocketDatagramPacket

image-20250206145243265

1. 案例一:一发一收

实现客户端发送一条消息,服务端接收到消息并显示出来。

首先编写服务端代码:

java
public static void main(String[] args) throws IOException {
    // 1. 创建服务端程序,监听8888端口
    DatagramSocket socket = new DatagramSocket(8888);

    // 2. 创建数据包,用于接收数据
    byte[] buffer = new byte[1024 * 64];
    DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length);

    // 3. 接收数据(阻塞)
    socket.receive(datagramPacket);

    // 4. 处理数据
    int length = datagramPacket.getLength();
    byte[] data = datagramPacket.getData();

    String str = new String(data, 0, length, Charset.forName("UTF-8"));
    System.out.println(str);

    // 5. 关闭资源
    socket.close();
}

然后编写客户端代码:

java
public static void main(String[] args) throws IOException {
    // 1. 创建客户端程序
    DatagramSocket socket = new DatagramSocket();

    // 2. 准备数据包,该数据包包括服务端地址
    byte[] bytes = "我是客户端".getBytes(Charset.forName("UTF-8"));
    DatagramPacket datagramPacket = new DatagramPacket(
            bytes,
            bytes.length,
            new InetSocketAddress("127.0.0.1", 8888)
    );

    // 3. 发送数据
    socket.send(datagramPacket);

    // 4. 关闭客户端
    socket.close();
}

2. 案例二:多发多收

实现客户端从控制台获取用户输入,并发送给服务端,服务端接收多条消息并显示出来。当用户输入exit时,退出客户端。

服务端代码:

java
public static void main(String[] args) throws IOException {
    // 1. 创建服务端程序,监听8888端口
    DatagramSocket socket = new DatagramSocket(8888);

    // 2. 创建数据包,用于接收数据
    byte[] buffer = new byte[1024 * 64];
    DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length);

    while (true) {
        // 3. 接收数据(阻塞)
        socket.receive(datagramPacket);

        // 4. 处理数据
        int length = datagramPacket.getLength();
        byte[] data = datagramPacket.getData();
        InetAddress address = datagramPacket.getAddress();  // 获取客户端地址
        int port = datagramPacket.getPort();   // 获取客户端端口

        String str = new String(data, 0, length, Charset.forName("UTF-8"));
        System.out.println(address.getHostAddress() + ":" + port + "发送:" + str);
    }
}

客户端代码:

java
public static void main(String[] args) throws IOException {
    // 1. 创建客户端程序
    DatagramSocket socket = new DatagramSocket();

    Scanner scanner = new Scanner(System.in);
    while (true) {
        System.out.print("请输入:");
        String input = scanner.nextLine();
        if("exit".equals(input)){
            // 4. 退出程序,关闭客户端
            socket.close();
            break;
        }

        // 2. 准备数据包,该数据包包括服务端地址
        byte[] bytes = input.getBytes(Charset.forName("UTF-8"));
        DatagramPacket datagramPacket = new DatagramPacket(
                bytes,
                bytes.length,
                new InetSocketAddress("127.0.0.1", 8888)
        );

        // 3. 发送数据
        socket.send(datagramPacket);
    }
}

在上面的服务端代码中,可以通过DatagramPacket获取客户端地址,这样服务端也可以给客户端发送消息。

首先客户端代码另开一个线程接收数据:

java
public class ClientDemo {
    public static void main(String[] args) throws IOException {
        // 1. 创建客户端程序
        DatagramSocket socket = new DatagramSocket();

        // 另开一个线程接收数据
        new Thread(new Receive(socket)).start();

        Scanner scanner = new Scanner(System.in);
        while (true) {
            String input = scanner.nextLine();
            if ("exit".equals(input)) {
                // 4. 退出程序,关闭客户端
                socket.close();
                break;
            }

            // 2. 准备数据包,该数据包包括服务端地址
            byte[] bytes = input.getBytes(Charset.forName("UTF-8"));
            DatagramPacket datagramPacket = new DatagramPacket(
                    bytes,
                    bytes.length,
                    new InetSocketAddress("127.0.0.1", 8888)
            );

            // 3. 发送数据
            socket.send(datagramPacket);
        }

    }
}

@Slf4j
class Receive implements Runnable {
    private DatagramSocket socket;

    public Receive(DatagramSocket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            while (true) {
                byte[] buffer = new byte[1024 * 64];
                DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length);

                socket.receive(datagramPacket);

                int length = datagramPacket.getLength();
                byte[] data = datagramPacket.getData();
                InetAddress address = datagramPacket.getAddress();  // 获取客户端地址
                int port = datagramPacket.getPort();   // 获取客户端端口

                String str = new String(data, 0, length, Charset.forName("UTF-8"));
                log.info(address.getHostAddress() + ":" + port + " 返回:" + str);
            }
        } catch (IOException e) {
            log.error("接收服务端消息异常:{}",e.getMessage());
        }

    }
}

服务端代码在接收到客户端数据后,原样返回数据:

java
public class ServerDemo {
  public static void main(String[] args) throws IOException {
      // 1. 创建服务端程序,监听8888端口
      DatagramSocket socket = new DatagramSocket(8888);

      // 2. 创建数据包,用于接收数据
      byte[] buffer = new byte[1024 * 64];
      DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length);

      while (true) {
          // 3. 接收数据(阻塞)
          socket.receive(datagramPacket);

          // 4. 处理数据
          int length = datagramPacket.getLength();
          byte[] data = datagramPacket.getData();
          InetAddress address = datagramPacket.getAddress();  // 获取客户端地址
          int port = datagramPacket.getPort();   // 获取客户端端口

          String str = new String(data, 0, length, Charset.forName("UTF-8"));
          System.out.println(address.getHostAddress() + ":" + port + " 发送:" + str);

          // 5. 发送数据
          socket.send(datagramPacket);
      }
  }
}