【问题标题】:java NIO join to multicast channel on the default network interfacejava NIO 加入到默认网络接口上的多播通道
【发布时间】:2024-01-03 04:44:02
【问题描述】:

我正在使用 java.nio.channels.DatagramChannel 来发送和接收 UDP 多播消息。运行我的程序的盒子可以有多个网络接口。

我可以为传出数据报使用套接字选项手动指定网络接口:

NetworkInterface ni = NetworkInterface.getByName("eth0");
channel.setOption(StandardSocketOptions.IP_MULTICAST_IF, ni);

并通过网络接口加入传入数据报的方法:

MembershipKey key = channel.join(group, ni);

但我希望我的应用使用基于路由表的默认界面。对于传出数据,这很容易。我不应该指定 IP_MULTICAST_IF 或将 null 作为网络接口传递。 Java 文档说以下内容:

"此套接字选项的初始/默认值可能为 null 以 表示输出接口将由操作选择 系统,通常基于网络路由表。”

但是传入的数据是什么。 “join”方法总是需要指定网络接口,并且不允许我传递null。

理想情况下,我希望在与该多播组完全相同的接口上加入多播组,默认情况下,该接口用于传出数据报。

有什么办法吗?

我正在使用 Java 8 和 Linux 操作系统。

【问题讨论】:

    标签: java udp nio multicast multicastsocket


    【解决方案1】:

    DatagramChannel API 中没有任何明确支持在系统选择的接口上加入多播组,但您可以通过使用 MulticastSocket::getNetworkInterface 来获取占位符 NetworkInterface 来解决它。所以这应该做你想要的:

    NetworkInterface ni;
    try (MulticastSocket s = new MulticastSocket()) {
        ni = s.getNetworkInterface();
    }
    
    MembershipKey key = channel.group(join, ni);
    

    创建 MulticastSocket 只是为了调用 getNetworkInterface。

    【讨论】:

    • 好东西。这实际上可能是最接近的事情。几年前,我无法让这种方法在具有许多接口的机器上可靠地工作,但现在可能效果更好。唯一的问题是没有(还)为MulticastSocket 指定组,因此数据报可能最终会出现在意外的网络上。
    • 这个解决方案看起来很奇怪。但它有效!非常感谢!!!
    • @Daniel 我们不需要为 MulticastSocket 指定组,组播套接字在 try 块完成后自动关闭,我们仅使用它来获取 INADDR_ANY 或 0.0.0.0 的 NetworkInterface 对象实例。 .
    【解决方案2】:

    TL;DR 我认为不可能让它按照你想要的方式工作。至少在 Java 中不是。

    关于 D 类(多播)地址的一点是,它们对几乎任何有能力的 NIC 都有效。即使对于同一个多播组,发送和接收之间也没有一致性。我可以在一个接口上发送到229.111.222.333,并在另一个接口上加入/收听同一个多播组。由于 UDP 是无会话的,因此这种设置非常好。

    即使操作系统能够选择正确的接口,它们中的大多数也不能,这就是您需要指定它的原因。但是,如果机器充当多播路由器(例如运行mrouted),那么情况就完全不同了,因为它的路由功能通常由/etc/mrouted.conf 控制。

    例如,如果我为我的带有两个 NIC 的 Windows 机器转储路由表(我知道您使用的是 Linux,但它通常不会显示 D 类地址的路由表条目。我相信这是一个提示; -)),我得到了这个(省略了不相关的条目):

    Network Destination        Netmask          Gateway       Interface  Metric
            224.0.0.0        240.0.0.0         On-link         127.0.0.1    131
            224.0.0.0        240.0.0.0         On-link       192.168.1.1    281
            224.0.0.0        240.0.0.0         On-link    172.89.123.123    281
    

    如您所见,如果我发送或收听224.123.123.123,操作系统将不知道选择哪个接口,它们都同样符合条件。它可能使用Metric 值,但在这种情况下,在环回接口上使用多播毫无意义。 D类地址是奇怪的鸟,上面240.0.0.0的“结束地址”被标记为Netmask,而显然不是。

    "此套接字选项的初始/默认值可能为 null 以 表示输出接口将由操作选择 系统,通常基于网络路由表。”

    我认为这不是一个完全准确的说法。或者,如果您在一个多宿主盒子上,并且 一个 接口上设置了 MULTICAST 标志,则可能是这样。但是如果您有多个,那么也许您可以使用ip add route 明确添加特定的路由/网卡,但我怀疑它会起作用。

    多年来,我在众多操作系统中完成或使用的所有多播编程商业产品都要求我指定要在哪个 NIC 上执行操作。 p>

    【讨论】:

    • 不确定 Windows 和其他操作系统,但 linux 允许我们在您加入多播组时传递 INADDR_ANY。当我在 C 上实现此功能时,它可以完美运行。旧的 java.net.MulticastSocket 有一个参数的方法 join,我没有尝试过,但它似乎也应该可以正常工作。大多数操作系统允许我们使用多个物理和逻辑网络接口,并为不同地址配置默认路由。
    最近更新 更多