14

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およびlinklocal= falseの3番目のVMwareインターフェースがあるため、これらのフィールドも役に立ちません。

4

4 に答える 4

22

私のラップトップ(仮想ボックスとそのネットワークインターフェイスがインストールされているWindows 7を実行している)では、次のコードがワイヤレスインターフェイスの名前とローカルアドレスを出力します。一日の終わりにブルートフォースアプローチを使用しますが、実際には最良の候補と見なされるアドレスにのみ接続しようとします。

// 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;
  }
}

(私はモッカーティムのisReachable(...)答えに基づいて私の答えを更新しました。)

注意すべきことが1つあります。socket.bind(...)接続が十分に高速にクリーンアップされていないなど、コードを連続して高速に実行しようとすると、アドレスとポートがすでに使用されていることに吠えます。8080多分ランダムなポートである必要があります。

于 2011-12-11T07:26:22.387 に答える
5

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

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

アップデート:

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

更新2:

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

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

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

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;
}
于 2015-12-03T21:28:17.187 に答える
1

私はかなり長い間同じ問題に悩まされていました。最初の質問は何年も前に尋ねられましたが、とにかくこの問題についての私の見解を追加します。皮肉なことに、質問と一緒に答えが提供されました。
それは:これが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つの物理インターフェイスのみを返すはずです。

于 2018-05-11T11:29:13.120 に答える