2011-12-11 32 views
11

如何確定使用Java將哪個網絡接口連接到互聯網?例如,我運行如何確定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接口本地=真和link local = false,所以這些字段不是'也沒有任何幫助。

+0

你運行一個虛擬機內部的JAR(可以用二進制邏輯進行優化)的VM是它自己的環境,擁有自己的網絡接口,這是什麼? Java返回什麼結果 – blackcompe

+0

N o,這是在Windows 7機器上。然而,我安裝了VMWare,我相信這是它用來與虛擬機進行通信的接口。我不確定爲什麼Java選擇這個接口作爲默認值。這種行爲是在我的室友計算機(Windows 7,VMWare安裝)相同 –

+0

@CavynVonDeylen請看我更新的答案。我發佈的代碼只打印出我真實的網絡界面,而我已經安裝並啓用了Virtual Box的網絡。 –

回答

17

在我的筆記本電腦上(運行Windows 7,使用Virtual Box並安裝了網絡接口),以下代碼會打印出我的無線接口名稱以及本地地址。它在一天結束時使用強力方法,但只會嘗試並實際連接到被認爲是最佳候選人的地址。

// 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(...)。)

有一點要注意。socket.bind(...)會咆哮我,如果我試圖連續運行我的代碼太快,連接速度不夠快,地址和端口已被佔用。 8080應該是一個隨機端口也許。

+0

這會返回我想要的接口以及我的計算機上的兩個VMWare接口。我想要的界面是第一個,但我並不想一直依靠這種說法。 –

+0

@CavynVonDeylen如果你可以描述你的用例,我們可以提出*某種解決方案。但是,沒有* clean *的方法來做到這一點。我的第一個猜測是你應該通過他們的IP過濾地址:扔掉地址*而不是*以'192.168.1'開頭。是的,這是*野蠻*。 –

+0

謝謝!此代碼適用於我。我很驚訝Java沒有提供一些簡單的方法來做到這一點,因爲我認爲這將是一個相當普遍的問題。也許在Java 8中。 –

5

請看Java教程中的Retrieving Network InterfacesListing Network Interface Addresses

如果您有多個啓動並運行的網絡接口,則必須以編程方式選擇程序應使用的網絡接口。

UPDATE:

我發現這個問題類似於你的。
查看how-to-check-if-internet-connection-is-present-in-java的回答。

更新2:

恕我直言,你應該做在你的程序如下:

  1. 發現,你的程序在運行的機器上的所有IPv4網絡接口;
  2. 詢問用戶你的程序應該使用哪一個;
  3. 使用用戶指向的界面。
+1

我可以拿出我的機器上所有接口的一個奢侈列表,但我還沒有找到任何方式來以編程方式確定哪個接口連接到互聯網。我假設,如果我硬編碼「net4」,例如,恰好是我的機器上的正確界面,這不適用於運行我的程序的其他計算機。 –

+0

@CavynVonDeylen看到我的更新。 – MockerTim

1

我有同樣的問題,以及與此解決方案(不徹底的答案來了,但我需要的東西,並沒有嘗試連接到互聯網的基礎上爲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; 
} 
相關問題