如何在Java中确定Internet网络接口
如何确定使用Java连接到Internet的网络接口? 例如,我跑
InetAddress.getLocalHost().getHostAddress();
在Eclipse中,这完全返回我想要的内容,192.168.1.105。 但是,如果我将其打包到jar文件并运行该程序,则代码返回169.254.234.50。 看看这个,我发现这是我机器上的VMware虚拟以太网适配器接口的IP地址。
有没有办法确定连接到互联网的接口,但同时保持我的代码的可移植性?
接口比较
界面[net4]
display name : Intel(R) Centrino(R) Ultimate-N 6300 AGN MTU : 1500 loopback : false point to point: false up : true virtual : false multicast : true HW address : 00 24 D7 2C 5F 70 INET address (IPv4): 192.168.1.105 host name : MyComputer canonical host name : MyComputer loopback : false site local : true any local : false link local : false multicast : false reachable : true
界面[eth5]
display name : VMware Virtual Ethernet Adapter for VMnet1 MTU : 1500 loopback : false point to point: false up : true virtual : false multicast : true HW address : 00 50 56 C0 00 01 INET address (IPv4): 169.254.234.50 host name : MyComputer canonical host name : MyComputer loopback : false site local : false any local : false link local : true multicast : false reachable : true
还有第三个VMware接口,其中site local = true且link local = false,因此这些字段也没有任何帮助。
在我的笔记本电脑上(运行Windows 7,安装了Virtual Box及其网络接口),以下代码会打印出我的无线接口的名称以及我的本地地址。 它在一天结束时使用蛮力方法,但只会尝试并实际连接到被认为是最佳候选者的地址。
// iterate over the network interfaces known to java Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); OUTER : for (NetworkInterface interface_ : Collections.list(interfaces)) { // we shouldn't care about loopback addresses if (interface_.isLoopback()) continue; // if you don't expect the interface to be up you can skip this // though it would question the usability of the rest of the code if (!interface_.isUp()) continue; // iterate over the addresses associated with the interface Enumeration addresses = interface_.getInetAddresses(); for (InetAddress address : Collections.list(addresses)) { // look only for ipv4 addresses if (address instanceof Inet6Address) continue; // use a timeout big enough for your needs if (!address.isReachable(3000)) continue; // java 7's try-with-resources statement, so that // we close the socket immediately after use try (SocketChannel socket = SocketChannel.open()) { // again, use a big enough timeout socket.socket().setSoTimeout(3000); // bind the socket to your local interface socket.bind(new InetSocketAddress(address, 8080)); // try to connect to *somewhere* socket.connect(new InetSocketAddress("google.com", 80)); } catch (IOException ex) { ex.printStackTrace(); continue; } System.out.format("ni: %s, ia: %s\n", interface_, address); // stops at the first *working* solution break OUTER; } }
(我根据Mocker Tim的回答用isReachable(...)
更新了我的答案。)
有一点需要注意。 socket.bind(...)
会socket.bind(...)
我的地址和端口已经在使用,如果我试图连续运行我的代码太快,就像连接没有足够快地清理一样。 8080
应该是随机端口。
请参阅Java教程中的检索网络接口和列出网络接口地址 。
如果有多个已启动并运行的网络接口,则必须以编程方式选择程序应使用的网络接口。
更新:
我发现了与你相似的问题。
请参阅如何检查如何检查互联网连接是否存在于java中的答案。
更新2:
恕我直言你应该在你的程序中执行以下操作:
- 查找运行程序的计算机上的所有IPv4网络接口;
- 询问用户你的程序应该使用哪些;
- 使用用户指向的界面。
我遇到了同样的问题,并提出了这个解决方案(不像答案那么彻底,但我需要一些不试图连接到互联网的东西。
基于已知的mac地址OUI: http : //standards-oui.ieee.org/oui.txt
我做了一个快速检查(可以用二进制逻辑优化)
private static boolean isVmwareMac(byte[] mac) { byte invalidMacs[][] = { {0x00, 0x05, 0x69}, //VMWare {0x00, 0x1C, 0x14}, //VMWare {0x00, 0x0C, 0x29}, //VMWare {0x00, 0x50, 0x56} //VMWare }; for (byte[] invalid: invalidMacs){ if (invalid[0] == mac[0] && invalid[1] == mac[1] && invalid[2] == mac[2]) return true; } return false; }
我被相同的问题所困扰了很多次,尽管很久以前就问过这个问题我还是会把这个问题附加到我的问题上。 具有讽刺意味的是,答案与问题一起提供。
它是: siteLocal = true
这对我有用
-
获取所有网络接口
NetworkInterface.getNetworkInterfaces();
-
单出当前失效的那些(只减少运行次数)
if(interface.isUp()){}
-
获取您刚刚挑出的接口的InetAddresses
interface.getInetAddresses();
-
检查这些地址是否为站点本地地址
if(inetAddress.isSiteLocal()){}
这应该为您提供一个/所有InetAddress(es) – 以及与您的本地网络链接的网络接口。
站点本地定义为使用来自这些网络的地址:10.0.0.0,172.16.0.0,192.168.0.0,而VirtualBox适配器和其他通常使用169.254.0.0链接本地地址。 IPv6还实现了站点本地概念,因此最好在此处关注IPv4。 在常规的最终用户计算机上,这应该可以很好地工作并返回一个物理接口。