2013-07-17 38 views
15

Tôi có ba giao diện (eth0,Loopback,wlan0) trên máy của mình và tôi muốn sử dụng Java-API để lấy địa chỉ mac.NetworkInterface.getNetworkInterfaces() không liệt kê tất cả các giao diện

  • Tôi sử dụng mã này.

    Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces(); 
        for (NetworkInterface netint : Collections.list(nets)) 
         displayInterfaceInformation(netint); 
    } 
    
    static void displayInterfaceInformation(NetworkInterface netint) 
        throws SocketException 
    { 
        System.out.println("Display name: " 
         + netint.getDisplayName()); 
        System.out.println("Hardware address: " 
         + Arrays.toString(netint.getHardwareAddress())); 
    } 
    
  • Nhưng mã in wlan0,loopback, nhưng nhỡ eth0.

  • Hệ điều hành của tôi Ubuntu, mọi trợ giúp.

Cập nhật

  • Các o/p (strace -f java Networks 2>&1| grep ioctl) .. trống (trống).

  • java -version

phiên bản java "1.7.0_21" Java (TM) SE Runtime Environment (xây dựng 1.7.0_21-b11) Java HotSpot (TM) 64-Bit Server VM (xây dựng 23,21 -b01, chế độ hỗn hợp)

  • strace ifconfig 2> & 1 | grep ioctl

ioctl(4, SIOCGIFCONF, {80, {{"lo", {AF_INET, inet_addr("127.0.0.1")}}, {"wlan0", {AF_INET, inet_addr("192.168.1.101")}}}}) = 0 
ioctl(5, SIOCGIFFLAGS, {ifr_name="eth0", ifr_flags=IFF_UP|IFF_BROADCAST|IFF_MULTICAST}) = 0 
ioctl(5, SIOCGIFHWADDR, {ifr_name="eth0", ifr_hwaddr=-----------------}) = 0 
ioctl(5, SIOCGIFMETRIC, {ifr_name="eth0", ifr_metric=0}) = 0 
ioctl(5, SIOCGIFMTU, {ifr_name="eth0", ifr_mtu=1500}) = 0 
ioctl(5, SIOCGIFMAP, {ifr_name="eth0", ifr_map={mem_start=0, mem_end=0, base_addr=0, irq=0, dma=0, port=0}}) = 0 
ioctl(5, SIOCGIFMAP, {ifr_name="eth0", ifr_map={mem_start=0, mem_end=0, base_addr=0, irq=0, dma=0, port=0}}) = 0 
ioctl(5, SIOCGIFTXQLEN, {ifr_name="eth0", ifr_qlen=1000}) = 0 
ioctl(4, SIOCGIFADDR, {ifr_name="eth0", ???}) = -1 EADDRNOTAVAIL (Cannot assign requested address) 
ioctl(5, SIOCGIFFLAGS, {ifr_name="lo", ifr_flags=IFF_UP|IFF_LOOPBACK|IFF_RUNNING}) = 0 
ioctl(5, SIOCGIFHWADDR, {ifr_name="lo", ifr_hwaddr=00:00:00:00:00:00}) = 0 
ioctl(5, SIOCGIFMETRIC, {ifr_name="lo", ifr_metric=0}) = 0 
ioctl(5, SIOCGIFMTU, {ifr_name="lo", ifr_mtu=16436}) = 0 
ioctl(5, SIOCGIFMAP, {ifr_name="lo", ifr_map={mem_start=0, mem_end=0, base_addr=0, irq=0, dma=0, port=0}}) = 0 
ioctl(5, SIOCGIFMAP, {ifr_name="lo", ifr_map={mem_start=0, mem_end=0, base_addr=0, irq=0, dma=0, port=0}}) = 0 
ioctl(5, SIOCGIFTXQLEN, {ifr_name="lo", ifr_qlen=0}) = 0 
ioctl(4, SIOCGIFADDR, {ifr_name="lo", ifr_addr={AF_INET, inet_addr("127.0.0.1")}}) = 0 
ioctl(4, SIOCGIFDSTADDR, {ifr_name="lo", ifr_dstaddr={AF_INET, inet_addr("127.0.0.1")}}) = 0 
ioctl(4, SIOCGIFBRDADDR, {ifr_name="lo", ifr_broadaddr={AF_INET, inet_addr("0.0.0.0")}}) = 0 
ioctl(4, SIOCGIFNETMASK, {ifr_name="lo", ifr_netmask={AF_INET, inet_addr("255.0.0.0")}}) = 0 
ioctl(5, SIOCGIFFLAGS, {ifr_name="wlan0", ifr_flags=IFF_UP|IFF_BROADCAST|IFF_RUNNING|IFF_MULTICAST}) = 0 
ioctl(5, SIOCGIFHWADDR, {ifr_name="wlan0", ifr_hwaddr=---------------}) = 0 
ioctl(5, SIOCGIFMETRIC, {ifr_name="wlan0", ifr_metric=0}) = 0 
ioctl(5, SIOCGIFMTU, {ifr_name="wlan0", ifr_mtu=1500}) = 0 
ioctl(5, SIOCGIFMAP, {ifr_name="wlan0", ifr_map={mem_start=0, mem_end=0, base_addr=0, irq=0, dma=0, port=0}}) = 0 
ioctl(5, SIOCGIFMAP, {ifr_name="wlan0", ifr_map={mem_start=0, mem_end=0, base_addr=0, irq=0, dma=0, port=0}}) = 0 
ioctl(5, SIOCGIFTXQLEN, {ifr_name="wlan0", ifr_qlen=1000}) = 0 
ioctl(4, SIOCGIFADDR, {ifr_name="wlan0", ifr_addr={AF_INET, inet_addr("192.168.1.101")}}) = 0 
ioctl(4, SIOCGIFDSTADDR, {ifr_name="wlan0", ifr_dstaddr={AF_INET, inet_addr("192.168.1.101")}}) = 0 
ioctl(4, SIOCGIFBRDADDR, {ifr_name="wlan0", ifr_broadaddr={AF_INET, inet_addr("192.168.1.255")}}) = 0 
ioctl(4, SIOCGIFNETMASK, {ifr_name="wlan0", ifr_netmask={AF_INET, inet_addr("255.255.255.0")}}) = 0 

ifconfig

$ ifconfig 
eth0  Link encap:Ethernet HWaddr ------------- 
      UP BROADCAST MULTICAST MTU:1500 Metric:1 
      RX packets:0 errors:0 dropped:0 overruns:0 frame:0 
      TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 
      collisions:0 txqueuelen:1000 
      RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) 

lo  Link encap:Local Loopback 
      inet addr:127.0.0.1 Mask:255.0.0.0 
      inet6 addr: ::1/128 Scope:Host 
      UP LOOPBACK RUNNING MTU:16436 Metric:1 
      RX packets:1695 errors:0 dropped:0 overruns:0 frame:0 
      TX packets:1695 errors:0 dropped:0 overruns:0 carrier:0 
      collisions:0 txqueuelen:0 
      RX bytes:129949 (129.9 KB) TX bytes:129949 (129.9 KB) 

wlan0  Link encap:Ethernet HWaddr ------------------- 
      inet addr:192.168.1.101 Bcast:192.168.1.255 Mask:255.255.255.0 
      inet6 addr: fe80::-------------- Scope:Link 
      UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 
      RX packets:8396 errors:0 dropped:0 overruns:0 frame:0 
      TX packets:5524 errors:0 dropped:0 overruns:0 carrier:0 
      collisions:0 txqueuelen:1000 
      RX bytes:3959941 (3.9 MB) TX bytes:1513934 (1.5 MB) 
+8

Có phải cấu hình eth0 không? Nó có hiển thị khi bạn thực hiện 'ifconfig' không? –

+0

Mã của bạn hoạt động cho tôi (Ubuntu 12.04 LTS) - nó hiển thị 'lo' và' eth0' –

+2

Như @Erik đã nói: đầu ra của 'ifconfig' là gì? Cả hai 'ifconfig' và Java API đều sử dụng cùng một lệnh' ioctl' ('SIOCGIFCONF'), vì vậy chúng phải nhất quán –

Trả lời

6

Rõ ràng, tôi đã sai ở địa điểm đầu tiên: mặc dù cả hai ifconfig và API Java đang sử dụng các syscalls ioctl() giống nhau, chúng hoạt động khác nhau.

Trước hết, các SIOCGIFCONF ioctl() được ghi chép lại như sau (xem http://linux.die.net/man/7/netdevice):

 
SIOCGIFCONF 
    Return a list of interface (transport layer) addresses. 
    ... 
    The kernel fills the ifreqs with all current L3 interface 
    addresses that are running. 

Vì vậy, SIOCGIFCONF ioctl() được sử dụng bởi cả hai ifconfig và API JAVA chỉ trả về chạy giao diện. Điều này cũng có thể được nhìn thấy trong đầu ra strace ifconfig ... từ câu hỏi - đầu tiên ioctl chỉ trả lại lowlan0, nhưng không eth0.

Sau đó, ở đâu, ifconfig nhận được số eth0 từ tất cả? Kiểm tra mã ifconfig nguồn (từ gói net-tools trên Debian/Ubuntu), chúng ta thấy rằng ifconfig không sử dụng kết quả từ ioctl() làm cơ sở cho việc đếm thiết bị mạng, nhưng trước hết là đọc /proc hệ thống tập tin để xác định tất cả giao diện mạng. Sau đó, nó sử dụng các syscalls ioctl() để xác định thêm thông tin về từng giao diện.

Thật không may, phương thức java.net.NetworkInterface.getByName() thậm chí không trả lại đối tượng giao diện mạng cho giao diện chưa được định cấu hình nếu chúng tôi chuyển tên rõ ràng, như eth0.

Về cơ bản, vẫn còn ba cách tiếp cận khác nhau để có được những địa chỉ phần cứng của tất cả thiết bị trên Linux:

  • Gọi ifconfig và phân tích đầu ra (nên phương sách cuối cùng)
  • Thực hiện một thư viện JNI để làm tương tự những gì ifconfig thực hiện (yêu cầu thư viện được chia sẻ phụ thuộc vào kiến ​​trúc)
  • Đọc dữ liệu trực tiếp từ các hệ thống tệp /proc/sys.

Tất cả các phương pháp này phụ thuộc vào hệ thống và không di động. Lợi ích của phương pháp tiếp cận thứ ba là nó có thể được thực hiện trong Java thuần túy . Sau đây là một việc thực hiện mẫu của cách tiếp cận thứ ba mà làm việc tốt trong môi trường của tôi:

static void printHardwareAddresses() throws SocketException { 
    if (System.getProperty("os.name").equals("Linux")) { 

     // Read all available device names 
     List<String> devices = new ArrayList<>(); 
     Pattern pattern = Pattern.compile("^ *(.*):"); 
     try (FileReader reader = new FileReader("/proc/net/dev")) { 
      BufferedReader in = new BufferedReader(reader); 
      String line = null; 
      while((line = in.readLine()) != null) { 
       Matcher m = pattern.matcher(line); 
       if (m.find()) { 
        devices.add(m.group(1)); 
       } 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

     // read the hardware address for each device 
     for (String device : devices) { 
      try (FileReader reader = new FileReader("/sys/class/net/" + device + "/address")) { 
       BufferedReader in = new BufferedReader(reader); 
       String addr = in.readLine(); 

       System.out.println(String.format("%5s: %s", device, addr)); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 

    } else { 
     // use standard API for Windows & Others (need to test on each platform, though!!) 
     ... 
    } 
} 
+0

Có thể bạn cũng sẽ biết cách giải quyết vấn đề này? https://stackoverflow.com/questions/45607188/not-receiving-all-network-interfaces-of-an-android-device –

0

Khi gọi getNetworkInterfaces Java sẽ trở lại

all the interfaces on this machine. Returns null if no network interfaces could be found on this machine.

Bạn không phải là duy nhất một cái với số này issue. Rõ ràng, trên Linux Java sẽ chỉ trả về các giao diện có địa chỉ IP được cấp phát (tức là các adapter được cấu hình).

Nhưng từ quan điểm ứng dụng của bạn (trừ khi bạn đang xây dựng một ứng dụng cấu hình mạng) có giao diện không có địa chỉ IP thì hoàn toàn không có. Bạn sẽ phải thăm dò ý kiến ​​cho các giao diện hoặc nhận chúng mỗi khi bạn truy cập, ví dụ: "Tùy chọn mạng" trong ứng dụng của bạn.

+0

Có thể bạn sẽ biết làm thế nào để giải quyết này là tốt? https://stackoverflow.com/questions/45607188/not-receiving-all-network-interfaces-of-an-android-device –

0

Mở rộng @Andreas câu trả lời, chúng ta có thể viết một kịch bản shell nhỏ như $ifconfg | grep "Link encap" > some_file và sau đó sẽ có một (chỉ có 3 dòng) tập tin nhỏ hơn để phân tích cú pháp và chọn mã thông báo đầu tiên trên mỗi dòng. Điều tương tự để nhận được HWaddress. Chúng tôi sẽ viết mã java ít hơn.

Tùy chọn khác có thể là sử dụng dấu phẩy Apache IOUtils.toString(new FileInputStream(<file_path>,US_ASCII)) để đọc cài đặt. Điều này sẽ loại bỏ mã I/O java lặp đi lặp lại trong giải pháp của anh ta.

+0

Có thể bạn cũng sẽ biết cách giải quyết vấn đề này? https://stackoverflow.com/questions/45607188/not-receiving-all-network-interfaces-of-an-android-device –

Các vấn đề liên quan