傳統單點傳送 伺服器對每個客戶端個別發送資料副本。若有 10,000 位觀眾觀看線上演唱會,伺服器需發送 10,000 份相同資料,頻寬消耗為單客戶端的 10,000 倍,極易造成網路擁塞。多點傳送 讓伺服器**僅發送一份資料**到特定多點傳送群組地址,所有加入該群組的客戶端均可接收,頻寬消耗固定,適合直播、股票行情、多人遊戲等場景。
| 方法 | 說明 |
MulticastSocket(int port) | 建立並綁定本地埠口接收封包 |
joinGroup(InetAddress group) | 加入多點傳送群組 |
leaveGroup(InetAddress group) | 離開群組 |
setTimeToLive(int ttl) | 設定封包跳數 (1=本地, 32=同站點, 64=地區, 128=全球) |
setNetworkInterface(NetworkInterface ni) | 指定發送/接收網卡 (多網卡環境必要) |
完整範例:MCClient (接收端)
import java.io.IOException;
import java.net.*;
public class MCClient {
public static void main(String[] args) throws IOException {
// 1. 建立 Socket 綁定接收埠口
try (MulticastSocket socket = new MulticastSocket(10000)) {
// 2. 解析群組地址
InetAddress group = InetAddress.getByName("231.0.0.1");
// 3. 加入群組
socket.joinGroup(group);
System.out.println("已加入群組 " + group + ",等待資料...");
// 4. 接收 10 個封包
for (int i = 0; i < 10; i++) {
byte[] buffer = new byte[256];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet); // 阻塞等待
// 5. 精確提取實際資料長度 (避免印出緩衝區殘留空白)
byte[] data = new byte[packet.getLength()];
System.arraycopy(packet.getData(), 0, data, 0, packet.getLength());
System.out.println("收到 [" + packet.getLength() + " bytes]: " + new String(data));
}
// 6. 離開群組
socket.leaveGroup(group);
} // try-with-resources 自動 socket.close()
}
}
完整範例:MCServer (發送端)
import java.io.IOException;
import java.net.*;
public class MCServer {
public static void main(String[] args) throws IOException {
System.out.println("伺服器啟動,發送 30,000 筆資料到 231.0.0.1:10000");
// 1. 建立 Socket (不綁定特定埠口,僅發送)
try (MulticastSocket socket = new MulticastSocket()) {
InetAddress group = InetAddress.getByName("231.0.0.1");
// 2. 準備 DatagramPacket (目標地址+埠口)
byte[] dummy = new byte[0];
DatagramPacket packet = new DatagramPacket(dummy, 0, group, 10000);
// 3. 發送迴路
for (int i = 0; i < 30000; i++) {
String msg = "Video line " + i;
byte[] data = msg.getBytes(); // 平台預設編碼,建議指定 StandardCharsets.UTF_8
packet.setData(data);
packet.setLength(data.length);
socket.send(packet);
if (i % 5000 == 0) System.out.println("已發送 " + i + " 筆");
}
}
System.out.println("發送完成");
}
}
編譯與執行步驟
javac MCServer.java MCClient.java
# 終端機 1:啟動伺服器
java MCServer
# 終端機 2, 3...:啟動多個客戶端
java MCClient
進階主題與生產環境注意事項
1. 介面綁定 (多網卡環境)
NetworkInterface ni = NetworkInterface.getByName("eth0"); // 或 getByInetAddress
socket.setNetworkInterface(ni);
避免封包從錯誤網卡發出/接收。
2. TTL 設定控制傳播範圍
socket.setTimeToLive(1); // 僅本機 (測試用)
socket.setTimeToLive(32); // 同站點
socket.setTimeToLive(64); // 區域網路
3. IPv6 多點傳送
InetAddress group = InetAddress.getByName("ff0e::1"); // IPv6 多點地址
MulticastSocket socket = new MulticastSocket(10000);
socket.joinGroup(new InetSocketAddress(group, 10000), NetworkInterface.getByName("eth0"));
JDK 7+ joinGroup(SocketAddress, NetworkInterface) 支援 IPv6 Scope ID。
4. 可靠性增強
- 應用層序號 + 重傳請求 (NACK)
- 前向糾錯 (FEC) / RaptorQ 編碼
- 搭配
DatagramChannel (NIO) 實現非阻塞高併發
5. 防火牆與路由器設定
- 允許 UDP 10000 埠口通訊
- 路由器啟用 IGMP Snooping / PIM-SM 正確轉發
- 雲端環境 (AWS/Azure/GCP) 需啟用多點傳送支援或改用 Pub/Sub 服務
總結
MulticastSocket 實現「一對多」高效資料分發,核心流程:建立 Socket → 解析群組地址 → joinGroup → 收發 DatagramPacket → leaveGroup。
- 基於 UDP,**不保證可靠性**,適用於即時性優先、可容忍丟包的場景。
- 生產部署需考量網卡綁定、TTL、IPv6、防火牆、路由器 IGMP/PIM 設定。
- 現代替代方案:WebSocket (全雙工)、Server-Sent Events (單向)、gRPC Streaming、訊息佇列 (Kafka, RabbitMQ) 等提供更高層級的可靠分發。
- 上一篇文章: Java 學習路線圖:從入門到精通的系統化指南
- 下一篇文章: Java 網路程式設計基礎(下):DatagramSocket 與 UDP 無連線通訊
Copyright ©
程式碼之家 All Rights Reserved