UDP网络通信第二篇,翻译自国外网站。
原文:Broadcasting and Multicasting in Java
第一篇是UDP开发入门指南。
1.简介
本文主要介绍了如何在Java中实现广播和多播(组播)通信。广播和多播的概念基于UDP协议。
参考文章:单播,组播(多播),广播以及任播
我们首先快速回顾下数据报和广播以及它是在Java中如何实现的。说明了一些广播的缺点,而多播可以作为广播的一种替代方案。
最后,我们在讨论IPv4和IPv6中对这两种寻址方法的支持时得出结论。
2.数据报回顾
根据Java官方定义,“数据报是一种完整独立的信息,通过网络发送的数据报不保证其到达、到达时间和其内容”。
Java包 java.net 包含了通过UDP协议进行通信的两个类DatagramPacket和 DatagramSocket 。UDP常用在低延迟、不需要可靠性的场景,如音视频流、网络发现(局域网通信的上下线通知)等等。
要了解UDP和数据报的内容,请参考第一篇-UDP开发入门指南-Java。
3.广播
广播是one-to-all的一种通信类型,即会向在同一个链路(网络)中的所有节点发送数据报。与点对点(P2P)通信不同,广播并不知道目标主机地址。而是通过广播地址来发送数据报。
按照Ipv4协议,广播地址是一种逻辑地址,与地址关联的,连接到网络的设备能够收到数据报。在示例中,我们使用一个特别的IP地址,255.255.255.255,该地址作为本地网络中的广播地址。
根据定义,连接本地网络和其他网络的路由器并不会将发送给默认广播地址的数据报转发出去。稍后我们将演示如何遍历所有的网卡,并将数据报发给他们各自的广播地址。
首先,我们先演示如何广播一条消息。要实现此功能,我们需要调用socket中的setBroadcast()方法,让它知道数据报需要被广播。
private static DatagramSocket socket = null;
public static void main((String[] args)) throws IOException {
broadcast("Hello", InetAddress.getByName("255.255.255.255"));
}
public static void broadcast(
String broadcastMessage, InetAddress address) throws IOException {
socket = new DatagramSocket();
socket.setBroadcast(true);
byte[] buffer = broadcastMessage.getBytes();
DatagramPacket packet
= new DatagramPacket(buffer, buffer.length, address, 4445);
socket.send(packet);
socket.close();
}
}
下面这段代码通过迭代找到所有网卡中对应的广播地址。
List<InetAddress> listAllBroadcastAddresses() throws SocketException {
List<InetAddress> broadcastList = new ArrayList<>();
Enumeration<NetworkInterface> interfaces
= NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface networkInterface = interfaces.nextElement();
if (networkInterface.isLoopback() || !networkInterface.isUp()) {
continue;
}
networkInterface.getInterfaceAddresses().stream()
.map(a -> a.getBroadcast())
.filter(Objects::nonNull)
.forEach(broadcastList::add);
}
return broadcastList;
}
一旦得到广播地址列表,我们就可以执行broadcast() method的代码,根据不同的广播地址发送一条广播消息。。
接受广播消息不需要特别的代码。可以复用UDP开发指南中的代码(待翻译)。
原文:A Guide To UDP in Java
4.多播(组播)
广播是向本地网络中的所有节点发给广播消息,而不管该节点是否需要,所以效率不高,浪费资源。
多播解决了该问题,它只向感兴趣的节点发送消息。多播基于组概念,一个多播地址代表一个组。
在IPv4地址中, 224.0.0.0 到 239.255.255.255之间的地址可以作为多播地址。只有订阅组的节点才能接受组数据报。
多播使用D类地址。因此,如果从首位开始到第4位是“1110”,就可以认为是多播地址。而剩下的28位可以成为多播的组编号。
---《图解TCP/IP》
在Java中,MulticastSocket 是用来接受发往多播地址的数据报。下面的例子演示了如何使用 MulticastSocket:
public class MulticastReceiver extends Thread {
protected MulticastSocket socket = null;
protected byte[] buf = new byte[256];
public void run() {
socket = new MulticastSocket(4446);
InetAddress group = InetAddress.getByName("230.0.0.0");
socket.joinGroup(group);
while (true) {
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
String received = new String(
packet.getData(), 0, packet.getLength());
if ("end".equals(received)) {
break;
}
}
socket.leaveGroup(group);
socket.close();
}
}
MulticastSocket绑定端口后,调用joinGroup()方法,以多播地址作为参数。要接收该组的数据报必须调用此方法。leaveGroup()方法是离开组。
下面的代码展示了如何向多播地址发送消息。
public class MulticastPublisher {
private DatagramSocket socket;
private InetAddress group;
private byte[] buf;
public void multicast(
String multicastMessage) throws IOException {
socket = new DatagramSocket();
group = InetAddress.getByName("230.0.0.0");
buf = multicastMessage.getBytes();
DatagramPacket packet
= new DatagramPacket(buf, buf.length, group, 4446);
socket.send(packet);
socket.close();
}
}
5.广播和IPv6
IPv4支持三种类型的编址:单播、广播和多播。理论上,多播是一对所有的通信,来自某一设备的数据报可以发往整个网络中可到达的所有节点。
由于显而易见的原因,因此IPv4广播的范围显着缩小。
多播虽然也是广播的一种更好的替代方案,但在很晚的时候才出现,因此在采用方面落后。
Ipv6中,已经强制要求多播支持,并且没有明确的广播概念。在IPv6中,多播已得到扩展和改进。因此,因此现在可以通过某种形式的多播来实现所有广播功能。
在Ipv6中,IP地址的最左边的几位用来决定其类型。对于多播地址,其前八位都是1,例如 FF00::/8。另外113-116 代表地址的范围,可以代表如下四种的某一种:全球、本地点、本地链路、本地节点
除了单播和多播,Ipv6还支持任播(anycast)。任播可以将包发给组内的任一成员,而不必发送给本组的所有成员。
6.总结
在本文中,我们研究了UDP协议中的one-to-all和one-to-many的通信类型的概念,并给出了Java中的实现代码。
最后,我们探讨了在IPv4和Ipv6的支持情况。
所有例子均可找到 over on Github.