У меня есть несколько странное требование иметь возможность прослушивать ряд сетевых интерфейсов из Java на машине с Linux и определять, получает ли один из них UDP-пакеты определенного типа. Выходные данные, которые мне нужны, - это IP-адрес рассматриваемого интерфейса. Есть ли способ сделать это на Java?
Прослушивание подстановочного адреса (новый DatagramSocket(port)) не помогает, потому что, хотя я и получаю широковещательные пакеты, я не могу определить локальный 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-адресу является правильным поведением, хотя в винде это работает. Мне нужно, чтобы он работал в Linux (RHEL и Ubuntu). С низкоуровневым C-кодом есть обходной путь setsockopt(SO_BINDTODEVICE), который я не могу найти в Java-API. Это не внушает мне особого оптимизма :-)