UDP (User Datagram Protocol) 是無連接、不可靠、保留消息邊界的傳輸協議。Java 用 DatagramSocket (發送/接收端點) + DatagramPacket (數據容器) 實現。本文詳細講解:構造器、發送接收流程、地址/端口處理、端口掃描實戰、常見坑點。
| 類 | 關鍵構造/方法 | 說明 |
|---|---|---|
DatagramSocket | new DatagramSocket() (隨機端口) / new DatagramSocket(port) (指定端口) / new DatagramSocket(port, InetAddress) (指定網卡) / send(p) / receive(p) / close() | UDP 端點,綁定本地端口 |
DatagramPacket | new DatagramPacket(buf, len) (接收) / new DatagramPacket(buf, len, addr, port) (發送) / getAddress() / getPort() / getData() / getLength() / setLength() | 數據報容器,攜帶數據、目標/來源地址端口 |
InetAddress | getByName(host) / getHostAddress() | IP 地址封裝 |
// 1. 創建 Socket (發送端通常用隨機端口)
try (DatagramSocket socket = new DatagramSocket()) {
// 2. 準備數據
String msg = "Hello UDP";
byte[] data = msg.getBytes(StandardCharsets.UTF_8);
// 3. 解析目標地址
InetAddress target = InetAddress.getByName("192.168.1.100");
int port = 9000;
// 4. 構建發送包 (含目標地址端口)
DatagramPacket packet = new DatagramPacket(data, data.length, target, port);
// 5. 發送
socket.send(packet);
System.out.println("已發送至 " + target + ":" + port);
}
// 1. 創建 Socket 綁定固定端口 (接收端必須固定端口)
try (DatagramSocket socket = new DatagramSocket(9000)) {
byte[] buffer = new byte[4096]; // 足夠大緩衝區
while (true) {
// 2. 構建接收包 (無目標地址)
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
// 3. 阻塞接收
socket.receive(packet); // 此處阻塞直到有數據報到達
// 4. 解析數據
String msg = new String(packet.getData(), 0, packet.getLength(), StandardCharsets.UTF_8);
InetAddress sender = packet.getAddress();
int senderPort = packet.getPort();
System.out.printf("收自 %s:%d → %s%n", sender.getHostAddress(), senderPort, msg);
// 5. 重置長度供下次接收 (關鍵!)
packet.setLength(buffer.length);
}
}
public class UdpPortScanner {
public static void main(String[] args) {
String target = "127.0.0.1";
int startPort = 1024, endPort = 65535;
int openCount = 0;
for (int port = startPort; port <= endPort; port++) {
try (DatagramSocket socket = new DatagramSocket(port)) {
// 能綁定說明端口空閒
socket.close();
} catch (SocketException e) {
// 綁定失敗 = 端口被佔用
System.out.println("端口佔用: " + port);
openCount++;
}
}
System.out.println("掃描完成,共發現 " + openCount + " 個佔用端口");
}
}
原理:new DatagramSocket(port) 嘗試綁定端口,成功 = 空閒,失敗拋 SocketException = 被佔用。注意:需 socket.close() 釋放,否則後續端口無法綁定。
| 方法 | 發送包含義 | 接收包含義 |
|---|---|---|
getAddress() | 目標 IP | 發送方 IP |
getPort() | 目標端口 | 發送方端口 |
getData() | 待發送字節數組 | 接收到的字節數組 (含舊數據,需配合 getLength()) |
getLength() | 發送字節數 | 實際接收字節數 |
setLength(int) | 設置發送長度 | 必須重置為緩衝區長度,否則下次只能接收 ≤ 上次長度 |
socket.setBroadcast(true) + 發送至 255.255.255.255 (廣播) 或組播地址 224.0.0.0/4。StandardCharsets.UTF_8,跨平台無亂碼。UDP 通信核心:DatagramSocket 綁定端口、DatagramPacket 封裝數據與地址、send/receive 雙向交互、setLength 重置緩衝區。適用場景:DNS、NTP、視頻流、心跳、日誌傳輸、服務發現。掌握「不可靠」本質,在應用層按需補償可靠性,是用好 UDP 的關鍵。