Java查找默认网关的网络接口

8
在Java中,我想找到与用于到达默认网关的接口相对应的java.net.NetworkInterface。 接口的名称等事先不知道。
换句话说,如果以下是我的路由表,则我将需要与“bond0”对应的接口:
$ netstat -r
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
10.10.10.0     *               255.255.255.0   U         0 0          0 bond0
10.10.11.0     *               255.255.255.0   U         0 0          0 eth2
10.10.11.0     *               255.255.255.0   U         0 0          0 eth3
10.10.12.0     *               255.255.255.0   U         0 0          0 eth4
10.10.13.0     *               255.255.255.0   U         0 0          0 eth5
default         mygateway      0.0.0.0         UG        0 0          0 bond0

在进行了一些谷歌搜索之后,我仍然没有找到任何答案。

编辑:
Java运行时必须“知道”如何获取此信息(不是说它已经公开)。使用join(InetAddress grpAddr)调用(未指定接口)将java.net.MulticastSocket加入多播组时,表面上的行为似乎是在“默认”接口上加入(如上所述)。 这即使默认intf不是路由表中列出的第一个接口也可以正常工作。 但是,加入mcast组的底层POSIX调用需要此信息!

struct ip_mreqn group;
group.imr_multiaddr = ...
group.imr_address = **address of the interface!**
setsockopty(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group, sizeof(group));
要点:提供一种加入组播组的方法,不需要使用intf,Java平台隐含地必须知道如何在每个平台上确定适当的intf。
2个回答

7

我的方式是:

try(DatagramSocket s=new DatagramSocket())
{
    s.connect(InetAddress.getByAddress(new byte[]{1,1,1,1}), 0);
    return NetworkInterface.getByInetAddress(s.getLocalAddress()).getHardwareAddress();
}

由于使用数据报(UDP),它不会连接到任何地方,因此端口号可能是无意义的,远程地址(1.1.1.1)不必可达,只需可路由即可。


根据我的经验,这在Windows和IPv6上不起作用。即使绑定为v6套接字,getLocalAddress返回虚假的v4地址。 - the8472
在启用了Hyper-V的Windows10上,我使用Microsoft-android-emulator、docker和OpenVPN都能正常工作。 - AlexS
1
请注意,如果地址不可路由(例如,因为没有默认路由或者您在一个仅支持IPv6的网络上),那么NetworkInterface.getByInetAddress()将返回null。这是检测您是否拥有有效网络配置的好方法。 - Guss

0
据我所知,没有好的方法可以做到这一点,因为这些低级细节对于Java来说在跨平台方面非常困难。java.net.NetworkInterface可能会有所帮助,但如果可用的方法不足,您可能需要采取一些更丑陋的方法。
这是一些相关主题:
这是一些相关主题:

在Java中获取默认网关IP和MAC地址是否可能?

使用Java查找无线网络的SSID

这个程序将永远在指定的平台上运行吗?还是需要更具可移植性?最坏的情况下,您可以尝试执行系统命令并解析输出,但这不太可移植或稳定。

好的,我明白你的观点。然而,看起来该调用仍然需要一个地址,是吗?java.net.NetworkInterface可以获取接口(及其地址),稍微聪明一点就可以确定哪个接口拥有给定地址。我认为你的问题更加复杂,因为你首先要寻找低级路由信息,然后再向后查找与(默认)路由关联的接口。 - Carl
它需要多播地址(即224.xxx-239.xxx中的特殊地址),而不是接口地址。参数中没有提供此类信息。因此,“join”调用必须解决的问题是相同的。它会自动选择带有默认路由的那个(表现为明显的行为)。同样地,我想知道哪个接口具有默认路由。 - Josh
我猜,如果真的没有暴露的方法可以找到intf和def路由,我有点沮丧,因为在平台独立的方式下确定它的问题似乎已经在某个地方解决了。当然,要明确的是,我还没有“证明”join总是选择正确的intf(但从经验上看它总是有效的!)。所以我只能假设,在幕后,它知道... - Josh
明白了。所以如果它确实在底层解决了这个问题,你可以使用java.net.MulticastSocket加入默认接口,然后使用MulticastSocket.getNetworkInterfacegetInterface找出它选择的接口。然后离开组。当然,这并不是很安全,因为你没有理由打开多播套接字,所以这仍然不是一个理想的解决方案。 - Carl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接