NetworkInterface.getNetworkInterfaces()未列出所有接口 - java

我的机器上有三个接口(eth0,Loopback,wlan0),我想使用Java-API来获取mac地址。

  • 我使用此代码。
    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()));
    }
    
  • 但是该代码显示wlan0,loopback但错过了eth0
  • 我的操作系统Ubuntu,任何帮助。
  • 更新

  • o / p(strace -f java Networks 2>&1| grep ioctl).. 空白(空)
  • java -version
  • Java版本“1.7.0_21”
    Java(TM)SE运行时环境(内部版本1.7.0_21-b11)
    Java HotSpot(TM)64位服务器VM(内部版本23.21-b01,混合模式)

  • 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)
    

    参考方案

    显然,我一开始就错了:即使ifconfig和Java API都在使用
    相同的ioctl()系统调用,它们的行为会有所不同。

    首先,SIOCGIFCONF ioctl()记录如下(请参阅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.
    

    So, the SIOCGIFCONF ioctl() which is used by both ifconfig and the JAVA API only returns the running interfaces. This can also be seen in the strace ifconfig ... output from the question - the very first ioctl only returns lo and wlan0, but not eth0.

    Then, where does ifconfig get the eth0 from at all? Checking the ifconfig source code (from the net-tools package on Debian/Ubuntu), we see
    that ifconfig is not using the result from the ioctl() as the basis for the network device enumeration,
    but first of all reads the /proc filesystem to determine all network interfaces. Then, it uses the ioctl() syscalls to determine further information about each interface.

    Unfortunately, the java.net.NetworkInterface.getByName() method does not even return a network interface object
    for an unconfigured interface if we explicitly pass the name, like eth0.

    Essentially, there remain three different approaches to get the hardware addresses of all devices on Linux:

    • Call ifconfig and parse the output (should be last resort)
    • Implement a JNI library to do the same what ifconfig does (requires an architecture dependent shared library)
    • Read the data directly from the /proc and the /sys filesystems.

    All of these approaches are system dependant and not portable. The benefit of the third approach is that it can be
    implemented in pure Java. The following is a sample implementation of the third approach which worked well in my environment:

    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!!)
            ...
        }
    }
    

    Java-搜索字符串数组中的字符串 - java

    在Java中,我们是否有任何方法可以发现特定字符串是字符串数组的一部分。我可以避免出现一个循环。例如String [] array = {"AA","BB","CC" }; string x = "BB" 我想要一个if (some condition to tell wheth…

    Java Globbing模式以匹配目录和文件 - java

    我正在使用递归函数遍历根目录下的文件。我只想提取*.txt文件,但不想排除目录。现在,我的代码如下所示:val stream = Files.newDirectoryStream(head, "*.txt") 但是这样做将不会匹配任何目录,并且返回的iterator()是False。我使用的是Mac,所以我不想包含的噪音文件是.DS_ST…

    Java RegEx中的单词边界\ b - java

    我在使用\b作为Java Regex中的单词定界符时遇到困难。对于text = "/* sql statement */ INSERT INTO someTable"; Pattern.compile("(?i)\binsert\b");找不到匹配项Pattern insPtrn = Pattern.compile(&…

    Java Double与BigDecimal - java

    我正在查看一些使用双精度变量来存储(360-359.9998779296875)结果为0.0001220703125的代码。 double变量将其存储为-1.220703125E-4。当我使用BigDecimal时,其存储为0.0001220703125。为什么将它双重存储为-1.220703125E-4? 参考方案 我不会在这里提及精度问题,而只会提及数字…

    当回复有时是一个对象有时是一个数组时,如何在使用改造时解析JSON回复? - java

    我正在使用Retrofit来获取JSON答复。这是我实施的一部分-@GET("/api/report/list") Observable<Bills> listBill(@Query("employee_id") String employeeID); 而条例草案类是-public static class…