Contents

Java的广播和多播

1. 简介

在本文中,我们将描述如何在 Java 中处理一对多(广播)和一对多(多播)通信。本文中概述的广播和多播概念 基于 UDP 协议。

我们首先快速回顾一下数据报和广播以及它是如何在 Java 中实现的。我们还研究了广播的缺点,并建议将多播作为广播的替代方案。

最后,我们讨论了在IPv4 和 IPv6 中对这两种寻址方法的支持。

2. 数据报回顾

根据数据报的官方定义 ,“数据报是通过网络发送的独立、自包含的消息,其到达、到达时间和内容都无法保证”。

在 Java 中,java.net包公开了可用于通过 UDP 协议进行通信的DatagramPacket和*DatagramSocket类。*UDP 通常用于低延迟比保证交付更重要的场景,例如音频/视频流、网络发现等。

要了解有关 Java 中的 UDP 和数据报的更多信息,请参阅 Java中的 UDP 指南

3. 广播

广播是一种一对多类型的通信,即目的是将数据报发送到网络中的所有节点。与点对点通信不同, 我们不必知道目标主机的 IP 地址。而是使用广播地址。

根据 IPv4 协议,广播地址是一个逻辑地址,连接到网络的设备可以在该地址上接收数据包。在我们的示例中,我们使用特定的 IP 地址255.255.255.255,它是本地网络的广播地址。

根据定义,将本地网络连接到其他网络的路由器不会转发发送到此默认广播地址的数据包。稍后我们还将展示如何遍历所有NetworkInterfaces,并将数据包发送到它们各自的广播地址。

首先,我们演示如何广播消息。至此,我们需要在套接字上调用*setBroadcast()*方法,让它知道要广播该数据包:

public class BroadcastingClient {
    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();
    }
}

下一个片段显示了如何遍历所有NetworkInterfaces以找到它们的广播地址:

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()*方法中的代码。

接收方不需要特殊代码来接收广播消息。我们可以重用接收普通 UDP 数据报的相同代码。Java 中的 UDP 指南 包含有关此主题的更多详细信息。

4. 多播

广播是低效的,因为数据包被发送到网络中的所有节点,无论它们是否有兴趣接收通信。这可能是一种资源浪费。

多播解决了这个问题,并且只将数据包发送给那些感兴趣的消费者。多播基于组成员资格概念,其中多播地址代表每个组。

在 IPv4 中,224.0.0.0 到 239.255.255.255 之间的任何地址都可以用作多播地址。只有那些订阅组的节点才能接收与该组通信的数据包。

在 Java 中,MulticastSocket用于接收发送到多播 IP 的数据包。以下示例演示了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()*方法,将多播 IP 作为参数。这是能够接收发布到该组的数据包所必需的。*leaveGroup()*方法可用于离开组。

以下示例显示如何发布到多播 IP:

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 中,地址的最左边位用于确定其类型。对于组播地址,前8位全为1,即FF00::/8。此外,第 113-116 位表示地址的范围,可以是以下 4 种之一:Global、Site-local、Link-local、Node-local。

除了单播和多播,IPv6 还支持任播,其中一个数据包可以发送给组中的任何成员,但不需要发送给所有成员。