Stream Socket (TCP):連線導向、可靠、有序、流量控制,但建立連線需三次交握、維護狀態、開銷大。
Datagram Socket (UDP):無連線、不可靠、無序、無流控,但延遲低、開銷小、支援一對多 (廣播/多點傳送)。
+------------------+
| IP Header | (來源/目的 IP)
+------------------+
| UDP Header | (來源/目的 Port, Length, Checksum)
+------------------+
| Data (≤ 64KB) | 應用層資料
+------------------+
UDP 標頭僅 8 bytes,極度輕量。Checksum 提供基本錯誤檢測,失敗則靜默丟棄,不重傳、不通知發送端——像寄明信片,投遞不保證。
DatagramPacket:資料包容器,封裝資料位元組陣列 + 目的地址/埠 (發送) 或 來源地址/埠 (接收)。DatagramSocket:本地端點,綁定本地埠發送/接收資料包。MulticastSocket:DatagramSocket 子類,支援多點傳送群組加入/離開。| 建構子 | 適用場景 |
|---|---|
DatagramPacket(buf, length) | 接收端:預先分配緩衝區,稍後取得發送者資訊 |
DatagramPacket(buf, length, addr, port) | 發送端:一次性指定資料、目的地 |
DatagramPacket(buf, offset, length) | 進階:指定緩衝區偏移量 (零拷貝優化) |
DatagramPacket(buf, offset, length, addr, port) | 發送端 + 偏移量 |
// 建立一次,重複使用
byte[] dummy = new byte[0];
DatagramPacket packet = new DatagramPacket(dummy, 0, groupAddr, port);
for (String msg : messages) {
byte[] data = msg.getBytes(StandardCharsets.UTF_8); // 指定編碼
packet.setData(data);
packet.setLength(data.length);
socket.send(packet);
}
byte[] buffer = new byte[65507]; // UDP 最大承載 (65535 - 8 UDP - 20 IP)
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (running) {
socket.receive(packet); // 阻塞
// 處理資料
String received = new String(packet.getData(), 0, packet.getLength(), StandardCharsets.UTF_8);
InetAddress senderAddr = packet.getAddress();
int senderPort = packet.getPort();
// 回覆可直接用 packet.getAddress()/getPort() 建新包
}
setSoTimeout(int ms):設定 receive() 阻塞超時,避免永久阻塞,超時拋 SocketTimeoutException。setBroadcast(true):允許發送廣播封包 (255.255.255.255 或子網廣播位址)。setReuseAddress(true):允許多個 Socket 綁定同一埠 (SO_REUSEADDR),集群部署常用。setTrafficClass(int tc):設定 QoS (DiffServ/ToS),如 IPTOS_LOWDELAY。| 適用場景 | 不適用場景 |
|---|---|
| 即時語音/視訊 (丟包可容忍,延遲敏感) | 檔案傳輸、金融交易 (需可靠性) |
| DNS 查詢、NTP 時間同步 (請求小、單次交互) | 大數據傳輸 (需分片重組,效率極低) |
| 遊戲狀態同步 (最新狀態覆蓋舊狀態) | 需要嚴格順序/事務性的操作 |
| 服務發現、心跳檢測 (廣播/多點傳送) | 防火牆嚴格環境 (UDP 常被封鎖) |
若必須用 UDP 又需可靠性,應用層需實現:
不要重複造輪子!成熟專案請直接使用 Netty (UDP 支援)、QUIC/HTTP/3、gRPC over HTTP/2、RTP/RTCP (媒體流) 等標準協議框架。