问题
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:
- Use JNI to make the native call to
GetIfTable
yourself. - 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