java NIO 加入默认网络接口上的多播频道

java NIO join to multicast channel on the default network interface

我正在使用 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 医生说了以下内容:

"The initial/default value of this socket option may be null to indicate that outgoing interface will be selected by the operating system, typically based on the network routing tables."

但是传入数据是什么。方法"join"总是要求指定网络接口,不允许我传null。

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

有什么办法吗?

我正在使用 Java 8 和 Linux OS。

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

中没有

关于 class D(多播)地址的事情是它们对几乎所有可用的 NIC 都有效。发送和接收之间没有一致性,即使对于同一个多播组也是如此。我可以在一个接口上发送到 229.111.222.333,在另一个接口上发送到同一个多播组 join/listen。由于 UDP 是无会话的,因此这种设置非常好。

即使 OS 能够 select 正确的接口,他们中的大多数不能,这就是为什么你需要指定它。但是,如果机器充当多播路由器(例如 运行 mrouted),那么这是完全不同的事情,因为它的路由功能通常由 /etc/mrouted.conf.

控制

例如,如果我为我的 Windows 盒子转储路由 table 和两个 NIC(我知道你正在使用 Linux,但它通常不会显示路由table class 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,OS 将不知道选择哪个接口,它们都同样符合条件。它 可能 使用 Metric 值,但在这种情况下,在环回接口上使用多播没有意义。 Class D 地址是奇鸟,上面 240.0.0.0 的 "end address" 被标记为 Netmask 进一步支持了这一点,但显然不是。

"The initial/default value of this socket option may be null to indicate that outgoing interface will be selected by the operating system, typically based on the network routing tables."

我不认为这是一个完全准确的陈述。或者,如果您使用的是多宿主机,并且 一个 接口上设置了 MULTICAST 标志。但是,如果您有多个,那么 可能 您可以使用 ip add route 明确添加特定的 route/NIC,但我怀疑它是否有效。

所有的组播编程我多年来在众多操作系统上做过或使用过的商业产品,都要求我指定我想要操作的网卡

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

NetworkInterface ni;
try (MulticastSocket s = new MulticastSocket()) {
    ni = s.getNetworkInterface();
}

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

创建 MulticastSocket 只是为了调用 getNetworkInterface。