基礎概念
IP 多點傳送 (IP Multicast) 允許單一封包同時傳遞給多個接收者。D 類地址 224.0.0.0 ~ 239.255.255.255 保留為多點傳送群組地址。Java 提供 `java.net.MulticastSocket` 實現 UDP 基礎的多點傳送。
核心 API 速查
| 方法 | 用途 |
| `new MulticastSocket(port)` | 建立綁定本地埠的多點傳送 Socket |
| `joinGroup(InetAddress group)` | 加入多點傳送群組 |
| `leaveGroup(InetAddress group)` | 離開群組 |
| `setInterface(InetAddress iface)` | 指定發送/接收網卡 (多網卡環境) |
| `setTimeToLive(int ttl)` | 設定封包跳躍範圍 (0=本機, 1=同網段, 32=站內, 64=區域, 128=洲際, 255=全球) |
| `send(DatagramPacket p)` | 發送資料報 |
| `receive(DatagramPacket p)` | 阻塞接收資料報 |
發送端完整實現 (MulticastSender.java)
import java.io.*;
import java.net.*;
public class MulticastSender {
private static final int BUFSIZE = 1024;
private static final byte TTL = 1; // 僅本地網段
public static void main(String[] args) throws IOException {
if (args.length != 2) {
System.err.println("用法: java MulticastSender <多點傳送IP> <埠號>");
System.err.println("範例: java MulticastSender 230.0.0.1 8888");
return;
}
InetAddress group = InetAddress.getByName(args[0]);
int port = Integer.parseInt(args[1]);
try (MulticastSocket socket = new MulticastSocket()) {
socket.setTimeToLive(TTL);
System.out.println("已連線至 " + group + ":" + port + ",請輸入訊息 (Ctrl+D 結束):");
BufferedReader in = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
String line;
while ((line = in.readLine()) != null) {
byte[] buf = line.getBytes("UTF-8");
DatagramPacket packet = new DatagramPacket(buf, buf.length, group, port);
socket.send(packet);
System.out.println("已發送: " + line);
}
}
}
}
接收端完整實現 (MulticastReceiver.java)
import java.io.*;
import java.net.*;
public class MulticastReceiver {
private static final int BUFSIZE = 1024;
public static void main(String[] args) throws IOException {
if (args.length != 2) {
System.err.println("用法: java MulticastReceiver <多點傳送IP> <埠號>");
return;
}
InetAddress group = InetAddress.getByName(args[0]);
int port = Integer.parseInt(args[1]);
try (MulticastSocket socket = new MulticastSocket(port)) {
socket.joinGroup(group);
System.out.println("已加入群組 " + group + ":" + port + ",等待訊息...");
byte[] buf = new byte[BUFSIZE];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
while (true) {
socket.receive(packet);
String msg = new String(packet.getData(), 0, packet.getLength(), "UTF-8");
System.out.println("收自 " + packet.getAddress() + ": " + msg);
packet.setLength(BUFSIZE); // 重設長度供下次接收
}
}
}
}
編譯與執行驗證
# 終端機 1 (接收端)
java MulticastReceiver 230.0.0.1 8888
# 終端機 2 (發送端)
java MulticastSender 230.0.0.1 8888
輸入: Hello Multicast!
輸入: 第二條訊息
# 終端機 3 (另一接收端,同網段)
java MulticastReceiver 230.0.0.1 8888
# 同樣收到訊息
進階主題與避坑指南
| 主題 | 說明 |
| 防火牆/路由器 | 需開啟 IGMP Snooping、允許 UDP 埠通訊;跨子網需路由器支援 PIM-DM/SM |
| 多網卡選擇 | `socket.setInterface(InetAddress.getByName("192.168.1.100"))` 指定出介面 |
| 可靠性 | UDP 無序、丟包、重複;應用層需自行實現序號、ACK、重傳 (或改用 JGroups/Spread) |
| IPv6 多點傳送 | 地址前綴 `ff00::/8`,API 相同,僅換 `Inet6Address` |
| 生產級庫 | 推薦 JGroups (支援 TCP/UDP、狀態傳輸、分片、加密),野火即時通訊、Hazelcast 底層皆基於此 |
應用場景
- 股票行情即時推送 (單源、多讀)
- 叢集節點發現與心跳 (如 Elasticsearch Zen Discovery 早期版本)
- 視訊會議、IPTV 直播串流
- 分散式快取失效廣播 (如 Redis Cluster 構想)