2011-02-03 115 views
15

對於我的項目,我希望獲得所有可用廣播地址的列表,以便我可以廣播請求,並且位於未指定網絡中其他計算機上的其他應用程序將響應並獲取列表我(現在用邁克的貢獻小修改版)想出了這個:在Java中檢測所有可用網絡的廣播地址

 

private ArrayList<InetAddress> getBroadcastAddresses() { 
     ArrayList<InetAddress> listOfBroadcasts = new ArrayList(); 
     Enumeration list; 
     try { 
      list = NetworkInterface.getNetworkInterfaces(); 

      while(list.hasMoreElements()) { 
       NetworkInterface iface = (NetworkInterface) list.nextElement(); 

       if(iface == null) continue; 

       if(!iface.isLoopback() && iface.isUp()) { 
        System.out.println("Found non-loopback, up interface:" + iface); 

        Iterator it = iface.getInterfaceAddresses().iterator(); 
        while (it.hasNext()) { 
         InterfaceAddress address = (InterfaceAddress) it.next(); 

         System.out.println("Found address: " + address); 

         if(address == null) continue; 
         InetAddress broadcast = address.getBroadcast(); 
         if(broadcast != null) listOfBroadcasts.add(broadcast); 
        } 
       } 
      } 
     } catch (SocketException ex) { 
      return new ArrayList<InetAddress>(); 
     } 

     return site; 
} 
 

它工作得很好reqular LAN然而,當涉及到無線局域網,它只是跳過第二while循環一個步驟,因爲後有address等於零,即使當我用System.out.println(interfaceItem)只是查看接口正在通過它寫無線局域網的名稱和我的IP相應到網絡。

編輯1: This是172.16.1.104是我的IP在無線網絡中的輸出。這個問題只出現在我用Wifi的筆記本上。輸出來自我的筆記本,我主要使用無線,有時我使用UTP與我的朋友連接。我的筆記本上還有一個VirtualBox的網絡接口。

你能告訴我它有什麼問題嗎?謝謝!

注意:事實證明,這可能是我的筆記本的問題,特別是對於其他人而言,我喜歡這樣的問題:-)看起來像是死路一條,但感謝無論如何幫助:-)

仍然愛你! ;-)

+0

也許,只有一個內循環迭代是可以的,因爲你的網卡只有一個IP主機地址? – 2011-02-03 15:28:14

+0

我承認它不需要通過InterfaceAdresses,因爲在那裏,如你所說,應該只有一個,如果有的話,但即使現在也行不通? – Martin 2011-02-03 17:43:12

回答

5

我想你需要遍歷所有的地址,並且另外檢查廣播地址是否也是null

請考慮您可能有地址,您也不期望分配給接口。在我的Linux系統上,在您的代碼中,我看到的第一個地址是IPv6地址,空廣播(因爲不存在IPv6廣播這樣的事情 - 儘管您可以使用多播來實現相同的效果)。

您需要完全刪除1st way部分的代碼。當你continue;那裏你會去到下一個接口,而不是考慮有兩個地址的可能性。

你總是想迭代所有可以廣播的地址的另一個原因是你需要考慮你可能在分配給一個接口的兩個網絡上有地址。例如,您可能有一個分配了192.168.0.1/24172.16.0.1/24的接口。

另外,考慮使用Set來存儲廣播地址,以防止在同一子網上分配兩個地址的情況。

最後,由於使用廣播地址將限制您只與在同一子網中具有IP地址的主機通話,因此您可能會錯過使用相同子網/網絡掩碼正確配置的主機。所以你可能要考慮使用多播這一點;無論配置的地址如何,您都可以使用IPv4(或IPv6)所有節點的多播地址到達子網上的所有主機。 (224.0.0.1和FF01 :: 1,分別)

編輯 也對 2nd way錯誤,與您使用迭代器的。由於每次圍繞for循環獲得新的 .iterator(),幸運的是,這裏沒有無限循環。 我改變你的代碼,這一點,和它的作品對我來說:

$ cat Broadcasts.java 
import java.net.*; 
import java.util.*; 

public class Broadcasts 
{ 
    public static void main(String[] args) 
    { 
     HashSet<InetAddress> listOfBroadcasts = new HashSet<InetAddress>(); 
     Enumeration list; 
     try { 
      list = NetworkInterface.getNetworkInterfaces(); 

      while(list.hasMoreElements()) { 
       NetworkInterface iface = (NetworkInterface) list.nextElement(); 

       if(iface == null) continue; 

       if(!iface.isLoopback() && iface.isUp()) { 
        //System.out.println("Found non-loopback, up interface:" + iface); 

        Iterator it = iface.getInterfaceAddresses().iterator(); 
        while (it.hasNext()) { 
         InterfaceAddress address = (InterfaceAddress) it.next(); 
         //System.out.println("Found address: " + address); 
         if(address == null) continue; 
         InetAddress broadcast = address.getBroadcast(); 
         if(broadcast != null) 
         { 
          System.out.println("Found broadcast: " + broadcast); 
          listOfBroadcasts.add(broadcast); 
         } 
        } 
       } 
      } 
     } catch (SocketException ex) { 
      System.err.println("Error while getting network interfaces"); 
      ex.printStackTrace(); 
     } 

     // return listOfBroadcasts; 
    } 
} 

你可能會碰到的另一個問題是try/catch語句圍繞基本整個功能,這將導致該代碼停止,如果它擊中意外的事情。最好用try/catch來包圍可能的失敗點並做一些理智的事情(比如跳過界面或地址),但我沒有看到哪些方法可以拋出異常。

編輯2:我誤解了你的代碼;你的迭代器很好。 ;-)問題(我之前指出)是你的1st way短路了你的2nd way;因爲它碰到continue;聲明,如果第一個地址是null你甚至不嘗試遍歷它們。

無論如何,運行這些println聲明併發布結果,如果您仍然遇到問題。

編輯3:好的,我放棄了。 ;-)根據你發佈的輸出,看起來你正遇到NetworkInterface類中的一個bug。

我不知道這是否有助於關閉preferIPv4Stack選項,但您應該測試該選項。我周圍搜索了一些描述這種行爲的錯誤報告,但找不到任何信息。

既然你是在Linux上,你總是可以採取炮擊,並呼籲類似的後退方法:

/sbin/ip addr | perl -ne 'print "$1\n" if $_ =~ /inet.* brd ([0-9\.]*)/' 

...這應該回報你的廣播地址的列表。

編輯4:我剛剛在JavaDoc中注意到NetworkInterface有一個getSubInterfaces()調用。也許你需要調用這個以確保你獲得所有的地址? (它可以幫助發佈的/sbin/ip addr/sbin/ifconfig輸出)

編輯5:對於剛剛添加的賞金。 (這個問題已經超過一年了!)有人可以在我上面的答案中運行代碼(編輯以便於複製/粘貼/運行),並告訴我它是否有效?如果沒有,請編輯問題並記下確切的錯誤/問題。