Javaを使用してインターネットに接続されているネットワークインターフェイスをどのように判断しますか?たとえば、私は実行します
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
サイトlocal = trueとリンクlocal = falseの3番目のVMwareインターフェースがあるので、これらのフィールドも役に立ちません。
私のラップトップ(VirtualBoxとそのネットワークインターフェイスがインストールされたWindows7を実行している)では、次のコードがワイヤレスインターフェイスの名前とローカルアドレスを出力します。一日の終わりにブルートフォースアプローチを使用しますが、実際には最良の候補と見なされるアドレスに接続しようとするだけです。
_// iterate over the network interfaces known to Java
Enumeration<NetworkInterface> 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<InetAddress> 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's 回答に基づいてisReachable(...)
で回答を更新しました。)
注意すべきことが1つあります。 socket.bind(...)
は、接続が十分に高速にクリーンアップされていないなど、コードを連続して高速に実行しようとすると、アドレスとポートがすでに使用されていることを吠えます。 _8080
_はおそらくランダムポートである必要があります。
Javaチュートリアル)の ネットワークインターフェイスの取得 および ネットワークインターフェイスアドレスの一覧表示 をご覧ください。
稼働中のネットワークインターフェイスが複数ある場合は、プログラムで使用するネットワークインターフェイスをプログラムで選択する必要があります。
更新:
あなたに似た質問を見つけました。
how-to-check-if-internet-connection-is-present-in-Java の回答を参照してください。
更新2:
IMHOプログラムでは、次のことを行う必要があります。
私は同じ問題を抱えていて、この解決策を思いつきました(答えほど徹底的ではありませんが、インターネットに接続しようとしない何かが必要でした。
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()){}
これにより、1つまたはすべてのInetAddress(およびローカルネットワークにリンクされているネットワークインターフェイス)が提供されます。
サイトローカルは、10.0.0.0、172.16.0.0、192.168.0.0のネットワークからのアドレスを使用するように定義されていますが、VirtualBoxアダプターなどは通常169.254.0.0リンクローカルアドレスを使用します。 IPv6はサイトローカルの概念も実装しているため、ここではIPv4に焦点を当てるのが最善です。通常のエンドユーザーマシンでは、これはかなりうまく機能し、1つの物理インターフェイスのみを返すはずです。