У меня есть несколько странное требование - иметь возможность прослушивать несколько сетевых интерфейсов из Java на компьютере с Linux и определять, получает ли один из них пакеты UDP определенного типа. Выходные данные, которые мне нужны, это IP-адрес рассматриваемого интерфейса. Есть ли способ сделать это в Java?
Прослушивание по шаблону (новый DatagramSocket (порт)) не помогает, потому что, пока я получаю широковещательные пакеты, я не могу определить локальный IP-адрес интерфейса, через который они пришли. Прослушивание трансляций при привязке к определенному интерфейсу (новый DatagramSocket (порт, адрес)) вообще не принимает пакеты. Этот случай заслуживает примера кода, который показывает, что я пытаюсь сделать:
Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface ni = (NetworkInterface) interfaces.nextElement();
Enumeration addresses = ni.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress address = (InetAddress)addresses.nextElement();
if (address.isLoopbackAddress() || address instanceof Inet6Address)
continue; //Not interested in loopback or ipv6 this time, thanks
DatagramSocket socket = new DatagramSocket(PORT, address);
//Try to read the broadcast messages from socket here
}
}
Я также попытался инициализировать сокет широковещательным адресом, созданным на основе начала реального IP-адреса интерфейса, а остальные - в соответствии с правильной маской сети:
byte [] mask = { (byte)255, 0, 0, 0 };
byte[] addrBytes = InetAddress.getByName("126.5.6.7").getAddress();
for (int i=0; i < 4; i++) {
addrBytes[i] |= ((byte)0xFF) ^ mask[i];
}
InetAddress bcastAddr = InetAddress.getByAddress(addrBytes);
Это просто создает исключение BindException при создании DatagramSocket.
EDIT: BindException (java.net.BindException: невозможно назначить запрошенный адрес) от вызова конструктора DatagramSocket с широковещательным адресом (например, 126.255.255.255) поставляется только с последней версией Ubuntu 9.04 (вероятно, не Ubuntu , но проблема конкретной версии ядра, хотя). В Ubuntu 8.10 это работало так же, как и в выпуске Red Hat (RHEL 4.x), с которым я имею дело.
Очевидно, что получение пакетов при привязке к определенному локальному IP-адресу является правильным поведением , хотя в Windows это работает. Мне нужно, чтобы он работал на Linux (RHEL и Ubuntu). В низкоуровневом C-коде есть обходной путь setsockopt (SO_BINDTODEVICE), который я не могу найти в Java-API. Это точно не вызывает у меня оптимизма: -)