跳转到内容

Java DatagramSocket

来自代码酷


Java DatagramSocket 是 Java 网络编程中用于实现无连接、不可靠的数据报通信的核心类之一。它基于 UDP 协议,适用于需要低延迟但不要求可靠传输的场景,如视频流、在线游戏和 DNS 查询等。本文将详细介绍 `DatagramSocket` 的基本概念、使用方法、代码示例及实际应用。

概述[编辑 | 编辑源代码]

`DatagramSocket` 是 Java 提供的用于发送和接收数据报(Datagram)的类。与面向连接的 `Socket` 不同,`DatagramSocket` 是无连接的,每个数据报(`DatagramPacket`)独立传输,不保证顺序或可靠性。它的主要特点包括:

  • **无连接性**:无需建立持久连接。
  • **低开销**:比 TCP 更轻量,适合高频小数据包传输。
  • **不可靠性**:不保证数据报的到达或顺序。

核心类与方法[编辑 | 编辑源代码]

`DatagramSocket` 的核心方法包括:

  • `DatagramSocket()`:创建一个未绑定的套接字。
  • `DatagramSocket(int port)`:绑定到指定端口。
  • `send(DatagramPacket p)`:发送数据报。
  • `receive(DatagramPacket p)`:接收数据报。
  • `close()`:关闭套接字。

`DatagramPacket` 是数据报的载体,包含数据和目标地址:

  • `DatagramPacket(byte[] buf, int length)`:接收用数据报。
  • `DatagramPacket(byte[] buf, int length, InetAddress address, int port)`:发送用数据报。

基本用法示例[编辑 | 编辑源代码]

以下是一个简单的客户端-服务器示例,展示 `DatagramSocket` 的基本用法。

服务器端代码[编辑 | 编辑源代码]

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

public class UDPServer {
    public static void main(String[] args) throws Exception {
        // 创建 DatagramSocket,监听端口 9876
        DatagramSocket socket = new DatagramSocket(9876);
        byte[] receiveData = new byte[1024];

        while (true) {
            // 准备接收数据报
            DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
            socket.receive(receivePacket); // 阻塞直到收到数据

            // 解析数据
            String message = new String(receivePacket.getData(), 0, receivePacket.getLength());
            System.out.println("Received: " + message);

            // 获取客户端地址和端口
            InetAddress clientAddress = receivePacket.getAddress();
            int clientPort = receivePacket.getPort();

            // 发送响应
            String response = "ACK: " + message;
            byte[] sendData = response.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, clientAddress, clientPort);
            socket.send(sendPacket);
        }
    }
}

客户端代码[编辑 | 编辑源代码]

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

public class UDPClient {
    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket();
        InetAddress serverAddress = InetAddress.getByName("localhost");
        String message = "Hello, Server!";
        byte[] sendData = message.getBytes();

        // 发送数据报
        DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, serverAddress, 9876);
        socket.send(sendPacket);

        // 接收响应
        byte[] receiveData = new byte[1024];
        DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
        socket.receive(receivePacket);

        String response = new String(receivePacket.getData(), 0, receivePacket.getLength());
        System.out.println("Server Response: " + response);

        socket.close();
    }
}

输出示例[编辑 | 编辑源代码]

服务器输出:

Received: Hello, Server!

客户端输出:

Server Response: ACK: Hello, Server!

实际应用场景[编辑 | 编辑源代码]

`DatagramSocket` 适用于以下场景: 1. **实时应用**:如视频会议(低延迟比可靠性更重要)。 2. **广播/组播**:向多个客户端发送相同数据(如股票行情推送)。 3. **轻量级协议**:DNS 查询、SNMP 等。

广播示例[编辑 | 编辑源代码]

以下代码展示如何使用 `DatagramSocket` 实现广播:

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

public class BroadcastSender {
    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket();
        socket.setBroadcast(true); // 启用广播
        String message = "Broadcast Message";
        byte[] data = message.getBytes();

        // 发送到广播地址(如 255.255.255.255 或子网广播地址)
        DatagramPacket packet = new DatagramPacket(data, data.length, 
            InetAddress.getByName("255.255.255.255"), 9876);
        socket.send(packet);
        socket.close();
    }
}

高级主题[编辑 | 编辑源代码]

超时设置[编辑 | 编辑源代码]

通过 `setSoTimeout(int timeout)` 可以设置接收超时(毫秒):

socket.setSoTimeout(5000); // 5秒超时
try {
    socket.receive(packet);
} catch (java.net.SocketTimeoutException e) {
    System.out.println("Timeout reached!");
}

多线程处理[编辑 | 编辑源代码]

在高并发场景中,可以为每个客户端请求分配一个线程:

while (true) {
    DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
    socket.receive(packet);
    new Thread(() -> handlePacket(packet)).start();
}

性能与限制[编辑 | 编辑源代码]

  • **优点**:低延迟、无连接开销。
  • **缺点**:无拥塞控制、可能丢包或乱序。

总结[编辑 | 编辑源代码]

`DatagramSocket` 是 Java UDP 编程的核心工具,适合需要快速传输但容忍丢包的场景。通过本文的示例和解释,读者可以掌握其基本用法并了解实际应用中的注意事项。

sequenceDiagram participant Client participant Server Client->>Server: DatagramPacket (Hello!) Server->>Client: DatagramPacket (ACK: Hello!)