Java 中的广播和多播

一、介绍

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

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

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

2. 数据报回顾

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

在 Java 中,java.net包公开了DatagramPacketDatagramSocket类,可用于通过 UDP 协议进行通信。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种之一:全局、站点本地、链路本地、节点本地。

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

6. 总结

在本文中,我们探讨了使用 UDP 协议进行一对多和一对多类型通信的概念。我们看到了如何在 Java 中实现这些概念的示例。

最后,我们还探讨了 IPv4 和 IPv6 支持。

完整的示例代码可以在 Github 上找到

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值