web-dev-qa-db-ja.com

Java)でインターネットネットワークインターフェイスを決定する方法

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インターフェースがあるので、これらのフィールドも役に立ちません。

13
Cavyn VonDeylen

私のラップトップ(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_はおそらくランダムポートである必要があります。

20

Javaチュートリアル)の ネットワークインターフェイスの取得 および ネットワークインターフェイスアドレスの一覧表示 をご覧ください。

稼働中のネットワークインターフェイスが複数ある場合は、プログラムで使用するネットワークインターフェイスをプログラムで選択する必要があります。

更新:

あなたに似た質問を見つけました。
how-to-check-if-internet-connection-is-present-in-Java の回答を参照してください。

更新2:

IMHOプログラムでは、次のことを行う必要があります。

  1. プログラムが実行されているマシン上のすべてのIPv4ネットワークインターフェイスを検索します。
  2. プログラムでどちらを使用するかをユーザーに尋ねます。
  3. ユーザーが指定したインターフェースを使用します。
5
MockerTim

私は同じ問題を抱えていて、この解決策を思いつきました(答えほど徹底的ではありませんが、インターネットに接続しようとしない何かが必要でした。

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;
}
1
mateuscb

私は同じ問題にかなり悩まされていました。最初の質問は何年も前に尋ねられましたが、とにかくこの問題についての私の見解を追加します。皮肉なことに、質問と一緒に答えが提供されました。
それは:siteLocal = true
これが私のために働いたものです

  1. すべてのネットワークインターフェイスを取得する

    NetworkInterface.getNetworkInterfaces();
    
  2. 現在ダウンしているものを選び出します(実行回数を減らすだけです)

    if(interface.isUp()){}
    
  3. 選択したインターフェイスのInetAddressesを取得します

    interface.getInetAddresses();
    
  4. それらがサイトローカルアドレスである場合は、それらのアドレスを確認してください

    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つの物理インターフェイスのみを返すはずです。

0
Pauliman