Get name of a specific network interface in Java

。_饼干妹妹 提交于 2019-12-11 04:25:00

问题


I am using windows 10 and I would like to plug a device on my computer (which created a new network interface with the name "Ethernet 12" and description "foobar") and be able to set the IP address of this interface using Java. Using this link: Change Computer IP address using JAVA, I am able to configure the IP address of the interface. The issue I have is that I am not able, in java, to retrieve the name of the interface created by the device. From the documentation I found, I did the following:

    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));
    }

and got the following result:

    Display name: foobar
    Name: eth15
    Address 111.116.15.4

I expected the name to be "Ethernet 12" and not "eth15", which doesn't seem to make any sense. I noticed the same for all my other interface (wifi, ethernet, etc...). Since I need the real name of my interface (Ethernet 12) to configure the IP address with netsh (and not a random one like "eth15"), I am stuck...

Is there a reason why I am getting "eth15" as the name of my interface ?

Thank you


回答1:


Is there a reason why I am getting "eth15" as the name of my interface ?

That took some digging. In Java world, NetworkInterfaces are enumerated by java.net.NetworkInterface::getNetworkInterfaces() which calls the native java.net.NetworkInterface::getAll().

We can find the native source code for getAll() in OpenJDK 11 here where we find this comment:

/*
 * 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.
 */

So once upon a time, when Windows 95 was still a thing, someone decided not to read the actual Windows interface names, and instead use "our own convention". Why? No idea. I would have preferred getting a separate deviceName() and a ourOwnConventionWhichHasNothingToDoWithTheActualNameDeviceName(), but unfortunately I wasn't consulted.

The underlying Windows API call GetIfTable does return a name for each interface in the form an array of 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;

The JVM seems to read this array, then generate an "appropriate" name, and finally override the OS-provided name with the generated one.

In short, it doesn't look like the implementation has changed in many years, and it's probably impossible to change at this point without creating a completely new API. Otherwise you risk breaking people's code.

The way I see it, there are two ways to get the actual interface names:

  1. Use JNI to make the native call to GetIfTable yourself.
  2. Execute netsh and parse the response.

Both solutions are kinda ugly and require you to make sure you're running on Windows.



来源:https://stackoverflow.com/questions/58632235/get-name-of-a-specific-network-interface-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!