【问题标题】:NetworkInterface.getNetworkInterfaces() not listing all interfacesNetworkInterface.getNetworkInterfaces() 未列出所有接口
【发布时间】:2013-07-15 22:59:20
【问题描述】:

我的机器上有三个接口(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&gt;&amp;1| grep ioctl).. 空白(空)

  • java -version

java 版本“1.7.0_21” Java(TM) SE 运行时环境 (build 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)

【问题讨论】:

  • eth0 配置了吗?当你做ifconfig时它会出现吗?
  • 您的代码适用于我(Ubuntu 12.04 LTS) - 它显示 loeth0
  • 正如@Erik 所说:ifconfig 的输出是什么? ifconfig 和 Java API 最终都使用相同的 ioctl 调用 (SIOCGIFCONF),所以它们应该是一致的
  • @Erik Ekman 我的机器操作系统 Ubuntu 和 eth0 使用 ifconfig 显示。
  • 发现一个openjdk错误报告:bugs.openjdk.java.net/browse/JDK-8147071

标签: java


【解决方案1】:

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

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

SIOCGIFCONF 返回接口(传输层)地址列表。 ... 内核用所有当前的 L3 接口填充 ifreqs 正在运行的地址

所以,ifconfig 和 JAVA API 都使用的 SIOCGIFCONF ioctl() 只返回 running 接口。这也可以在问题的strace ifconfig ... 输出中看到 - 第一个ioctl 只返回lowlan0,但不是 eth0。

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

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

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

  • 调用ifconfig 并解析输出(应该是最后的手段)
  • 实现一个 JNI 库来执行 ifconfig 所做的相同操作(需要依赖于架构的共享库)
  • 直接从/proc/sys 文件系统读取数据。

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

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

【讨论】:

  • 嘿@Andreas 我正在为 OS X 寻找类似的解决方案.. [stackoverflow question here] (stackoverflow.com/q/53618361/2619129)。非常感谢任何帮助注册这个。谢谢。
【解决方案2】:

调用getNetworkInterfaces时Java会返回

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

issue 不只有你一个人。显然,在 Linux 上,Java 将只返回分配了 IP 地址的接口(即配置的适配器)。

但是从您的应用程序的角度来看(除非您正在构建一个网络配置应用程序),拥有一个没有 IP 地址的接口就像根本没有它一样。您必须在每次访问(例如,应用程序中的“网络首选项”)时轮询接口或获取它们。

【讨论】:

    【解决方案3】:

    扩展@Andreas 的答案,我们可以编写一个像$ifconfg | grep "Link encap" &gt; some_file 这样的小shell 脚本,然后将有一个更小的(只有3 行)文件来解析并选择每行的第一个标记。获取 HWaddress 的类似事情。我们将编写较少的 java 代码。

    其他选项可能是使用 Apache commons IOUtils.toString(new FileInputStream( &lt;file_path&gt;,US_ASCII)) 来读取设置。这将消除他的解决方案中重复的 java I/O 代码。

    【讨论】:

      猜你喜欢
      • 2011-12-01
      • 1970-01-01
      • 2021-01-03
      • 1970-01-01
      • 1970-01-01
      • 2021-10-03
      • 2016-05-30
      • 2016-07-06
      • 1970-01-01
      相关资源
      最近更新 更多