Получить имя определенного сетевого интерфейса в Java

Я использую Windows 10, и я хотел бы подключить устройство к своему компьютеру (которое создало новый сетевой интерфейс с именем «Ethernet 12» и описанием «foobar») и иметь возможность установить IP-адрес этого интерфейса с помощью Java. Используя эту ссылку: Изменить IP-адрес компьютера с помощью 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», что, похоже, не имеет никакого смысла. Я заметил то же самое для всех других моих интерфейсов (wi-fi, ethernet и т. д.). Поскольку мне нужно настоящее имя моего интерфейса (Ethernet 12) для настройки IP-адреса с помощью netsh (а не случайное, например «eth15»), я застрял...

Есть ли причина, по которой я получаю «eth15» в качестве имени моего интерфейса?

Спасибо


person David Lefaivre    schedule 30.10.2019    source источник
comment
Похоже, вы не одиноки: stackoverflow. ком/вопросы/38803545/   -  person Malt    schedule 30.10.2019


Ответы (1)


Есть ли причина, по которой я получаю «eth15» в качестве имени моего интерфейса?

Это потребовало некоторого копания. В мире Java NetworkInterfaces перечисляются java.net.NetworkInterface::getNetworkInterfaces(), что вызывает native java.net.NetworkInterface::getAll().

Мы можем найти собственный исходный код для getAll() в OpenJDK 11 здесь мы находим этот комментарий:

/*
 * 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 кажется прочитайте этот массив, затем генерировать "подходящее" имя и, наконец, переопределить предоставленное ОС имя сгенерированным.

Короче говоря, не похоже, что реализация изменилась за много лет, и, вероятно, на данный момент это невозможно изменить, не создав совершенно новый API. В противном случае вы рискуете взломать код людей.

Как я это вижу, есть два способа получить фактические имена интерфейсов:

  1. Используйте JNI, чтобы сделать собственный вызов GetIfTable самостоятельно.
  2. Выполните netsh и проанализируйте ответ.

Оба решения довольно уродливы и требуют от вас убедиться, что вы работаете в Windows.

person Malt    schedule 30.10.2019