【问题标题】:Get name of a specific network interface in Java获取 Java 中特定网络接口的名称
【发布时间】:2019-10-30 19:11:32
【问题描述】:

我正在使用 Windows 10,我想在我的计算机上插入一个设备(它创建了一个名为“Ethernet 12”和描述“foobar”的新网络接口)并能够设置该接口的 IP 地址使用 Java。使用此链接:Change Computer IP address using JAVA,我可以配置接口的 IP 地址。我遇到的问题是我无法在 java 中检索设备创建的接口的名称。从我找到的文档中,我做了以下事情:

    Enumeration<NetworkInterface> networkInterfaces =  NetworkInterface.getNetworkInterfaces();

    while(networkInterfaces.hasMoreElements())
    {
        NetworkInterface networkInterface = networkInterfaces.nextElement();

        if (networkInterface.isUp())
            System.out.println("Display name: " + networkInterface.getDisplayName() + "\nName: " + networkInterface.getName() + "\nAddress: " + networkInterface.getInterfaceAddresses().get(0));
    }

得到如下结果:

    Display name: foobar
    Name: eth15
    Address 111.116.15.4

我希望名称是“Ethernet 12”而不是“eth15”,这似乎没有任何意义。我注意到我的所有其他接口(wifi、以太网等)都是一样的。由于我需要我的接口(以太网 12)的真实名称来使用 netsh 配置 IP 地址(而不是像“eth15”这样的随机地址),所以我被卡住了......

我将“eth15”作为我的接口名称有什么原因吗?

谢谢

【问题讨论】:

标签: java jvm network-programming network-interface


【解决方案1】:

我将“eth15”作为我的接口名称有什么原因吗?

这需要一些挖掘。在 Java 世界中,NetworkInterfacesjava.net.NetworkInterface::getNetworkInterfaces() 枚举,它调用 native java.net.NetworkInterface::getAll()

我们可以在 OpenJDK 11 here 中找到 getAll() 的本机源代码,我们可以在其中找到以下注释:

/*
 * Windows implementation of the java.net.NetworkInterface native methods.
 * This module provides the implementations of getAll, getByName, getByIndex,
 * and getByAddress.
 *
 * Interfaces and addresses are enumerated using the IP helper routines
 * GetIfTable, GetIfAddrTable resp. These routines are available on Windows
 * 98, NT SP+4, 2000, and XP. They are also available on Windows 95 if
 * IE is upgraded to 5.x.
 *
 * Windows does not have any standard for device names so we are forced
 * to use our own convention which is based on the normal Unix naming
 * convention ("lo" for the loopback, eth0, eth1, .. for ethernet devices,
 * tr0, tr1, .. for token ring, and so on). This convention gives us
 * consistency across multiple Windows editions and also consistency with
 * Solaris/Linux device names. Note that we always enumerate in index
 * order and this ensures consistent device number across invocations.
 */

所以曾几何时,当 Windows 95 仍然存在时,有人决定不阅读实际的 Windows 接口名称,而是使用“我们自己的约定”。为什么?不知道。我更希望获得单独的 deviceName()ourOwnConventionWhichHasNothingToDoWithTheActualNameDeviceName(),但不幸的是,我没有被咨询。

底层 Windows API 调用 GetIfTable 确实以 MIB_IFROW 数组的形式返回每个接口的名称:

typedef struct _MIB_IFROW {
  WCHAR                   wszName[MAX_INTERFACE_NAME_LEN];
  IF_INDEX                dwIndex;
  IFTYPE                  dwType;
  DWORD                   dwMtu;
  DWORD                   dwSpeed;
  DWORD                   dwPhysAddrLen;
  UCHAR                   bPhysAddr[MAXLEN_PHYSADDR];
  DWORD                   dwAdminStatus;
  INTERNAL_IF_OPER_STATUS dwOperStatus;
  DWORD                   dwLastChange;
  DWORD                   dwInOctets;
  DWORD                   dwInUcastPkts;
  DWORD                   dwInNUcastPkts;
  DWORD                   dwInDiscards;
  DWORD                   dwInErrors;
  DWORD                   dwInUnknownProtos;
  DWORD                   dwOutOctets;
  DWORD                   dwOutUcastPkts;
  DWORD                   dwOutNUcastPkts;
  DWORD                   dwOutDiscards;
  DWORD                   dwOutErrors;
  DWORD                   dwOutQLen;
  DWORD                   dwDescrLen;
  UCHAR                   bDescr[MAXLEN_IFDESCR];
} MIB_IFROW, *PMIB_IFROW;

JVM 似乎是read this array,然后是generate an "appropriate" name,最后是override the OS-provided name with the generated one

简而言之,实现看起来很多年都没有改变,如果不创建全新的 API,现在可能无法改变。否则你可能会破坏别人的密码。

在我看来,有两种方法可以获取实际的接口名称:

  1. 使用 JNI 自己对 GetIfTable 进行本机调用。
  2. 执行netsh 并解析响应。

这两种解决方案都有点难看,并且要求您确保在 Windows 上运行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-15
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 2013-06-21
    • 2011-04-19
    • 2020-04-25
    相关资源
    最近更新 更多