NetworkInterface.getNetworkInterfaces()未列出所有接口 [英] NetworkInterface.getNetworkInterfaces() not listing all interfaces

查看:1517
本文介绍了NetworkInterface.getNetworkInterfaces()未列出所有接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have three interfaces (eth0,Loopback,wlan0) on my machine and i want to get use Java-API to get the mac address.


  • 我使用此代码。

  • I use this code.

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

    更新


    • 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,混合模式)

    java version "1.7.0_21" Java(TM) SE Runtime Environment (build 1.7.0_21-b11) Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)


    • strace ifconfig 2>& 1 | grep ioctl

    • 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()系统调用,它们的行为不同。

    Obviously, I was wrong in the first place: even though both ifconfig and the Java API are using the same ioctl() syscalls, they behave differently.

    首先, SIOCGIFCONF ioctl()记录如下(参见 http://linux.die.net/man/ 7 / netdevice ):

    First of all, the SIOCGIFCONF ioctl() is documented as follows (see 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.
    

    因此, SIOCGIFCONF ioctl()由<$ c使用$ c> ifconfig 且JAVA API仅返回正在运行的接口。这也可以在问题的 strace ifconfig ... 输出中看到 - 第一个 ioctl 只返回 lo wlan0 ,但 eth0。

    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.

    然后, ifconfig 从哪里获取 eth0 ?检查 ifconfig 源代码(来自Debian / Ubuntu上的 net-tools 包),我们看到
    那个 ifconfig 没有使用 ioctl()的结果作为网络设备枚举的基础,
    但首先读取 / proc 文件系统以确定所有网络接口。然后,它使用 ioctl()系统调用来确定有关每个接口的更多信息。

    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.

    不幸的是, java.net.NetworkInterface.getByName()如果我们显式传递名称,方法甚至不会为未配置的接口返回网络接口对象
    ,例如 eth0

    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.

    基本上,有三种不同的方法可以获取Linux上所有设备的硬件地址:

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


    • 调用 ifconfig 并解析输出(应该是最后的手段)

    • 实现JNI库以执行与 ifconfig 相同的操作(需要依赖于体系结构的共享库)

    • 直接从 / proc / sys 文件系统中读取数据。

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

    所有这些方法都依赖于系统而且不可移植。第三种方法的好处是它可以用纯Java实现
    。以下是在我的环境中运行良好的第三种方法的示例实现:

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

    这篇关于NetworkInterface.getNetworkInterfaces()未列出所有接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆