gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 22:47:26 25 4
gpt4 key购买 nike

我的机器上有三个接口(interface)(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).. blank(empty).

    <
  • 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(无法分配请求的地址)
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 seethat 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 objectfor 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 beimplemented 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 - NetworkInterface.getNetworkInterfaces() 没有列出所有接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17698971/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com