UDP(用户数据报协议)凭借其无连接的特性,支持灵活多样的通信模式。根据数据包发送目标的不同,主要分为以下三种:
单播 (Unicast)
定义:一对一通信。发送方将数据包发送给特定的单个接收方。
场景:普通的客户端 - 服务器通信(如 DNS 查询、即时消息)。
特点:目标地址是具体的单播 IP。
广播 (Broadcast)
定义:一对所有通信。发送方将数据包发送给当前局域网网段内的所有主机。
场景:局域网设备发现(如打印机搜索)、DHCP 请求、局域网聊天室公告。
特点:目标地址是特殊的广播地址(如 255.255.255.255),路由器通常不转发广播包,限制在本地子网。
组播 (Multicast)
定义:一对多通信。发送方将数据包发送给加入特定组播组的一组主机。
场景:视频会议、IPTV 直播、股票行情推送、多人在线游戏状态同步。
特点:目标地址是组播 IP 地址(224.0.0.0 ~ 239.255.255.255),只有主动“加入”该组的主机才能收到数据,支持跨路由传输(需网络设备支持)。
广播是将数据包发送到局域网内的每一台设备。
广播地址:IPv4 中,255.255.255.255 代表受限广播地址,表示当前子网内的所有主机。也可以计算特定子网的定向广播地址(如 192.168.1.255)。
接收条件:接收端程序必须绑定与发送端指定的相同端口,且操作系统防火墙允许该端口的 UDP 流量。
网络限制:广播包通常无法跨越路由器,只能在同一个物理或逻辑子网(VLAN)内传播。

开启广播权限:默认情况下,DatagramSocket 不允许发送广播。必须调用 socket.setBroadcast(true) 显式开启。
目标地址:使用 InetAddress.getByName("255.255.255.255")。
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPBroadcaster {
public static void main(String[] args) {
try {
int port = 9999; // 约定好的监听端口
// 1. 创建 DatagramSocket (发送端通常不需要绑定特定端口)
DatagramSocket socket = new DatagramSocket();
// 2. 【关键】允许发送广播包
socket.setBroadcast(true);
// 3. 准备消息
String message = "Hello Everyone! This is a LAN Broadcast.";
byte[] data = message.getBytes("UTF-8");
// 4. 设置目标地址为广播地址
InetAddress broadcastAddress = InetAddress.getByName("255.255.255.255");
// 5. 封装数据包
DatagramPacket packet = new DatagramPacket(data, data.length, broadcastAddress, port);
// 6. 发送
socket.send(packet);
System.out.println("广播消息已发送至端口 " + port + ": " + message);
// 7. 关闭
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}注意:接收端代码与普通 UDP 接收代码完全一致,只需绑定相同的端口(本例为 9999)即可收到广播消息。
组播是一种高效的“一对多”传输方式,介于单播和广播之间。
组播地址范围:224.0.0.0 到 239.255.255.255 (D 类地址)。
224.0.0.0 ~ 224.0.0.255:预留组播地址,用于本地网络协议(如 OSPF, RIP),路由器不转发。
224.0.1.0 ~ 238.255.255.255:全球范围可用的组播地址。
239.0.0.0 ~ 239.255.255.255:本地管理范围组播地址(类似私有 IP),常用于内部网络。
加入机制:接收方必须显式地加入 (Join) 某个组播组,网卡才会接收发往该组 IP 的数据包。
优势:相比广播,组播减少了网络拥塞,因为未加入组的主机不会处理数据包;相比单播,服务器只需发送一份数据,由网络设备负责复制分发。

专用类:接收端必须使用 MulticastSocket(DatagramSocket 的子类),因为它提供了加入和离开组播组的方法。
发送端:可以使用普通的 DatagramSocket,也可以使用 MulticastSocket。只需将目标 IP 设置为组播 IP 即可。
生命周期:接收端在退出前应调用 leaveGroup() 离开组,以便通知路由器停止转发数据。
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPMulticastSender {
public static void main(String[] args) {
try {
int port = 8888;
// 定义一个组播地址 (例如:224.0.0.1 是本地所有主机组)
// 实际开发建议使用 239.x.x.x 范围内的地址以避免冲突
String multicastIp = "224.0.0.1";
// 1. 创建 Socket (普通 DatagramSocket 即可发送组播)
DatagramSocket socket = new DatagramSocket();
// 2. 准备数据
String message = "Multicast Message: Stock Price Update - AAPL $150";
byte[] data = message.getBytes("UTF-8");
// 3. 解析组播地址
InetAddress group = InetAddress.getByName(multicastIp);
// 4. 封装数据包 (目标是组播 IP)
DatagramPacket packet = new DatagramPacket(data, data.length, group, port);
// 5. 发送
socket.send(packet);
System.out.println("组播消息已发送至组 " + multicastIp + ": " + message);
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class UDPMulticastReceiver {
public static void main(String[] args) {
try {
int port = 8888;
String multicastIp = "224.0.0.1";
// 1. 创建 MulticastSocket 并绑定端口
MulticastSocket socket = new MulticastSocket(port);
// 2. 【关键】加入组播组
InetAddress group = InetAddress.getByName(multicastIp);
socket.joinGroup(group);
System.out.println("已加入组播组: " + multicastIp + ",开始监听...");
byte[] buffer = new byte[1024];
// 3. 循环接收
while (true) {
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet); // 阻塞等待
String msg = new String(packet.getData(), 0, packet.getLength(), "UTF-8");
System.out.println("收到组播消息 [" + packet.getAddress().getHostAddress() + "]: " + msg);
// 简单演示,实际应用中可添加退出条件
if ("exit".equals(msg)) break;
}
// 4. 离开组播组并关闭 (通常在 finally 块或 shutdown hook 中执行)
socket.leaveGroup(group);
socket.close();
System.out.println("已离开组播组,连接关闭。");
} catch (Exception e) {
e.printStackTrace();
}
}
}防火墙拦截:
无论是广播还是组播,如果操作系统的防火墙(如 Windows Defender, iptables)拦截了 UDP 端口,消息将无法接收。开发测试时请确保放行对应端口的 UDP 流量。
虚拟机网络模式:
在使用 VMware 或 VirtualBox 运行多台虚拟机测试广播 / 组播时,务必将网络适配器设置为 “桥接模式 (Bridged)”。
若使用 “NAT 模式”,虚拟机处于不同的虚拟子网后,无法接收到宿主机的广播包,也无法相互通信。
TTL (Time To Live):
对于组播,可以通过 MulticastSocket.setTimeToLive(int ttl) 设置数据包的生命周期。
ttl=0:仅限本机。
ttl=1:仅限本地子网(默认值)。
ttl>1:可以跨越路由器传输到更远的网络。
组播地址选择:
避免使用 224.0.0.0 ~ 224.0.0.255 之间的地址,这些是保留给路由协议使用的。
推荐在开发中使用 239.255.0.0 ~ 239.255.255.255 范围内的地址,这些是本地管理范围的组播地址,不会泄露到公网,较为安全。
资源释放:
使用 MulticastSocket 时,程序退出前务必调用 leaveGroup()。虽然关闭 Socket 通常也会隐式离开组,但显式调用能更快地通知网络设备更新转发表,提高网络效率。