Java UDP通信案例实现
UDP(User Datagram Protocol)是一种无连接的传输层协议,适合实时性要求高但可以容忍少量丢包的应用场景。

基础UDP通信实现
UDP发送端(客户端)
import java.net.*;
public class UDPSender {
public static void main(String[] args) {
DatagramSocket socket = null;
try {
// 创建UDP套接字
socket = new DatagramSocket();
// 要发送的数据
String message = "Hello, UDP Server!";
byte[] sendData = message.getBytes();
// 指定接收方地址和端口
InetAddress address = InetAddress.getByName("localhost");
int port = 8888;
// 创建数据报包
DatagramPacket packet = new DatagramPacket(
sendData,
sendData.length,
address,
port
);
// 发送数据
socket.send(packet);
System.out.println("数据已发送: " + message);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (socket != null && !socket.isClosed()) {
socket.close();
}
}
}
}
UDP接收端(服务器)
import java.net.*;
public class UDPReceiver {
public static void main(String[] args) {
DatagramSocket socket = null;
try {
// 创建UDP套接字并绑定到指定端口
socket = new DatagramSocket(8888);
System.out.println("UDP服务器已启动,等待接收数据...");
while (true) {
// 创建接收缓冲区
byte[] receiveData = new byte[1024];
DatagramPacket packet = new DatagramPacket(receiveData, receiveData.length);
// 接收数据(阻塞方法)
socket.receive(packet);
// 提取数据
String message = new String(
packet.getData(),
0,
packet.getLength()
);
// 获取发送方信息
InetAddress senderAddress = packet.getAddress();
int senderPort = packet.getPort();
System.out.println("收到来自 " + senderAddress.getHostAddress() +
":" + senderPort + " 的数据: " + message);
// 可选:回复确认消息
String response = "消息已收到: " + message;
byte[] responseData = response.getBytes();
DatagramPacket responsePacket = new DatagramPacket(
responseData,
responseData.length,
senderAddress,
senderPort
);
socket.send(responsePacket);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (socket != null && !socket.isClosed()) {
socket.close();
}
}
}
}
双向通信示例
双向通信客户端
import java.net.*;
import java.util.Scanner;
public class UDPClient {
public static void main(String[] args) {
DatagramSocket socket = null;
Scanner scanner = new Scanner(System.in);
try {
socket = new DatagramSocket();
InetAddress serverAddress = InetAddress.getByName("localhost");
int serverPort = 9999;
// 启动接收线程
Thread receiveThread = new Thread(() -> {
try {
while (true) {
byte[] receiveData = new byte[1024];
DatagramPacket packet = new DatagramPacket(
receiveData,
receiveData.length
);
socket.receive(packet);
String message = new String(
packet.getData(),
0,
packet.getLength()
);
System.out.println("\n服务器回复: " + message);
System.out.print("请输入消息: ");
}
} catch (Exception e) {
// 套接字关闭时退出
}
});
receiveThread.start();
// 发送数据
while (true) {
System.out.print("请输入消息 (输入'quit'退出): ");
String message = scanner.nextLine();
if ("quit".equalsIgnoreCase(message)) {
break;
}
byte[] sendData = message.getBytes();
DatagramPacket packet = new DatagramPacket(
sendData,
sendData.length,
serverAddress,
serverPort
);
socket.send(packet);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (socket != null && !socket.isClosed()) {
socket.close();
}
scanner.close();
}
}
}
双向通信服务器
import java.net.*;
import java.util.concurrent.ConcurrentHashMap;
public class UDPServer {
private static ConcurrentHashMap<String, ClientInfo> clients = new ConcurrentHashMap<>();
public static void main(String[] args) {
DatagramSocket socket = null;
try {
socket = new DatagramSocket(9999);
System.out.println("UDP服务器已启动,监听端口: 9999");
while (true) {
byte[] receiveData = new byte[1024];
DatagramPacket packet = new DatagramPacket(receiveData, receiveData.length);
socket.receive(packet);
// 处理接收到的数据
String message = new String(
packet.getData(),
0,
packet.getLength()
);
InetAddress clientAddress = packet.getAddress();
int clientPort = packet.getPort();
String clientKey = clientAddress.getHostAddress() + ":" + clientPort;
// 保存客户端信息
clients.put(clientKey, new ClientInfo(clientAddress, clientPort));
System.out.println("收到客户端 [" + clientKey + "] 消息: " + message);
// 处理广播或单播
if (message.startsWith("@")) {
// 私聊功能
String[] parts = message.split(" ", 3);
if (parts.length >= 3) {
String targetKey = parts[0].substring(1);
String privateMessage = parts[2];
sendToClient(socket, targetKey, privateMessage);
}
} else {
// 广播消息
broadcast(socket, clientKey, message);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (socket != null && !socket.isClosed()) {
socket.close();
}
}
}
// 发送消息给指定客户端
private static void sendToClient(DatagramSocket socket, String clientKey, String message) {
ClientInfo client = clients.get(clientKey);
if (client != null) {
try {
byte[] data = message.getBytes();
DatagramPacket packet = new DatagramPacket(
data,
data.length,
client.address,
client.port
);
socket.send(packet);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 广播消息给所有客户端
private static void broadcast(DatagramSocket socket, String sender, String message) {
String broadcastMessage = sender + ": " + message;
byte[] data = broadcastMessage.getBytes();
clients.forEach((key, client) -> {
try {
DatagramPacket packet = new DatagramPacket(
data,
data.length,
client.address,
client.port
);
socket.send(packet);
} catch (Exception e) {
e.printStackTrace();
}
});
}
// 客户端信息类
static class ClientInfo {
InetAddress address;
int port;
ClientInfo(InetAddress address, int port) {
this.address = address;
this.port = port;
}
}
}
使用多线程处理多个客户端
import java.net.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class UDPThreadServer {
private static final int PORT = 7777;
private static ExecutorService threadPool = Executors.newFixedThreadPool(10);
public static void main(String[] args) {
DatagramSocket socket = null;
try {
socket = new DatagramSocket(PORT);
System.out.println("多线程UDP服务器已启动");
while (true) {
byte[] receiveData = new byte[1024];
DatagramPacket packet = new DatagramPacket(receiveData, receiveData.length);
socket.receive(packet);
// 将处理任务交给线程池
threadPool.execute(new ClientHandler(socket, packet));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (socket != null && !socket.isClosed()) {
socket.close();
}
threadPool.shutdown();
}
}
// 客户端处理器
static class ClientHandler implements Runnable {
private DatagramSocket socket;
private DatagramPacket packet;
public ClientHandler(DatagramSocket socket, DatagramPacket packet) {
this.socket = socket;
this.packet = packet;
}
@Override
public void run() {
try {
// 解析接收到的数据
String message = new String(
packet.getData(),
0,
packet.getLength()
);
System.out.println("处理来自 " +
packet.getAddress().getHostAddress() + " 的消息: " + message);
// 处理业务逻辑...
String response = "处理完成: " + message.toUpperCase();
// 发送响应
byte[] responseData = response.getBytes();
DatagramPacket responsePacket = new DatagramPacket(
responseData,
responseData.length,
packet.getAddress(),
packet.getPort()
);
socket.send(responsePacket);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
UDP通信的注意事项
数据大小限制
// UDP数据包最大为65507字节(64KB减去UDP和IP头) // 实际应用中建议控制在1472字节以内(避免IP分片) int MAX_UDP_PACKET_SIZE = 1472; byte[] data = new byte[MAX_UDP_PACKET_SIZE];
超时设置
// 设置接收超时
socket.setSoTimeout(3000); // 3秒超时
try {
socket.receive(packet);
} catch (SocketTimeoutException e) {
System.out.println("接收超时");
}
端口复用
// 允许端口复用 socket.setReuseAddress(true);
广播地址
// 发送广播消息
socket.setBroadcast(true);
InetAddress broadcastAddress = InetAddress.getByName("255.255.255.255");
// 或者获取子网广播地址
// InetAddress broadcastAddress = InetAddress.getByName("192.168.1.255");
UDP vs TCP 选择建议
/* UDP适用场景: 1. 实时性要求高(视频通话、游戏) 2. 容忍少量丢包 3. 简单查询-响应模式 4. 多播或广播通信 TCP适用场景: 1. 数据完整性要求高 2. 大量数据传输 3. 需要可靠连接 4. 文件传输、网页浏览 */
运行示例
- 先运行UDPReceiver或UDPServer
- 再运行UDPSender或UDPClient
- 观察控制台输出
这个案例提供了UDP通信的完整实现,包括单向通信、双向通信、多客户端处理和线程池应用,你可以根据实际需求选择和修改相应的代码。