Java на Linux: Слушание широковещательных сообщений на связанном локальном адресе

вероятно, отношение к модели объявления и пользователя

в модели AdDetail

public function ad()
{
return $this->belongsTo(Ad::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
6
задан auramo 11 May 2009 в 12:55
поделиться

5 ответов

В конечном итоге это была проблема ядра Linux IPV6. Обычно я отключаю IPV6, потому что он вызывает всякие головные боли. Однако в Ubuntu 9.04 так сложно отключить IPV6, что я сдался, и это меня укусило.

Чтобы прослушивать широковещательные сообщения от определенного интерфейса, я сначала создам «широковещательную версию» 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);

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

Затем я создаю датаграммный сокет с этим адресом (и желаемым портом), и он работает. Но не без передачи следующих системных свойств в JVM:

-Djava.net.preferIPv6Addresses=false -Djava.net.preferIPv4Stack=true 

Я понятия не имею, как IPV6 удается прервать прослушивание широковещательных рассылок, но это происходит, и вышеуказанные параметры исправляют это.

4
ответ дан 17 December 2019 в 04:51
поделиться

Not sure if this helps but I know that to get a list of all the network interfaces:

Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();

Maybe you can bind to each one independently?

Just found some great examples on the usage of getNetworkInterfaces().

0
ответ дан 17 December 2019 в 04:51
поделиться

Насколько мне известно, единственный способ сделать это - использовать параметр сокета

IP_RECVDSTADDR

. Эта опция должна гарантировать, что dst-адрес интерфейса, на который пришел пакет, доступен при привязке к подстановочному адресу. Полагаю, он должен работать и с широковещательной рассылкой.

Вот пример C, который я нашел в Интернете:

Как получить адрес назначения UDP для входящих пакетов

Я бы прочитал на recvmsg , а затем попытайтесь выяснить, доступен ли этот интерфейс в Java.

Изменить:

Я только что понял, что у вас может быть еще один вариант, если он поддерживается в Java. Возможно, вам все еще понадобится параметр сокета IP_RECVDSTADDR (не уверен), но вместо использования recvmsg вы можете использовать необработанный сокет и получить адрес назначения из заголовка IP.

Откройте сокет, используя SOCK_RAW , и вы получите полный IP-заголовок в начале каждого сообщения, включая адреса источника и назначения.

Вот пример использования UDP с необработанным сокетом в C в Linux:

Advanced TCP / IP - ПРИМЕРЫ ПРОГРАММЫ RAW SOCKET

Я был бы удивлен, если этот метод не работает и в Java.

Edit2

Еще одна идея. Есть ли причина, по которой вы не можете использовать многоадресную рассылку, или какая-то конкретная причина, по которой вы выбрали широковещательную рассылку вместо многоадресной? Насколько я понимаю, с многоадресной рассылкой вы всегда будете знать, на каком интерфейсе принимаются пакеты, поскольку вы всегда привязываетесь к определенному интерфейсу при присоединении к группе многоадресной рассылки (особенно с IP4, где вы привязываетесь к интерфейсу через один из его IP-адресов).

Я получу полный IP-заголовок в начале каждого сообщения, включая адреса источника и назначения.

Вот пример использования UDP с необработанным сокетом на C в Linux:

Advanced TCP / IP - ПРИМЕРЫ ПРОГРАММЫ RAW SOCKET

Я был бы удивлен, если этот метод не работает и в Java.

Edit2

Еще одна идея. Есть ли причина, по которой вы не можете использовать многоадресную рассылку, или какая-то конкретная причина, по которой вы выбрали широковещательную рассылку вместо многоадресной? Насколько я понимаю, с многоадресной рассылкой вы всегда будете знать, на каком интерфейсе принимаются пакеты, поскольку вы всегда привязываетесь к определенному интерфейсу при присоединении к группе многоадресной рассылки (особенно с IP4, где вы привязываетесь к интерфейсу через один из его IP-адресов).

Я получу полный IP-заголовок в начале каждого сообщения, включая адреса источника и назначения.

Вот пример использования UDP с необработанным сокетом в C в Linux:

Advanced TCP / IP - ПРИМЕРЫ ПРОГРАММЫ RAW SOCKET

Я был бы удивлен, если этот метод не работает и в Java.

Edit2

Еще одна идея. Есть ли причина, по которой вы не можете использовать многоадресную рассылку, или какая-то конкретная причина, по которой вы выбрали широковещательную рассылку вместо многоадресной? Насколько я понимаю, с помощью многоадресной рассылки вы всегда будете знать, на каком интерфейсе принимаются пакеты, поскольку вы всегда привязываетесь к определенному интерфейсу при присоединении к группе многоадресной рассылки (особенно с IP4, где вы привязываетесь к интерфейсу через один из его IP-адресов).

s пример использования UDP с необработанным сокетом в C в Linux:

Advanced TCP / IP - ПРИМЕРЫ ПРОГРАММЫ RAW SOCKET

Я был бы удивлен, если этот метод не работает и в Java.

Edit2

Еще одна идея. Есть ли причина, по которой вы не можете использовать многоадресную рассылку, или какая-то конкретная причина, по которой вы выбрали широковещательную рассылку вместо многоадресной? Насколько я понимаю, с помощью многоадресной рассылки вы всегда будете знать, на каком интерфейсе принимаются пакеты, поскольку вы всегда привязываетесь к определенному интерфейсу при присоединении к группе многоадресной рассылки (особенно с IP4, где вы привязываетесь к интерфейсу через один из его IP-адресов).

s пример использования UDP с необработанным сокетом в C в Linux:

Advanced TCP / IP - ПРИМЕРЫ ПРОГРАММЫ RAW SOCKET

Я был бы удивлен, если этот метод не работает и в Java.

Edit2

Еще одна идея. Есть ли причина, по которой вы не можете использовать многоадресную рассылку, или какая-то конкретная причина, по которой вы выбрали широковещательную рассылку вместо многоадресной? Насколько я понимаю, с многоадресной рассылкой вы всегда будете знать, на каком интерфейсе принимаются пакеты, поскольку вы всегда привязываетесь к определенному интерфейсу при присоединении к группе многоадресной рассылки (особенно с IP4, где вы привязываетесь к интерфейсу через один из его IP-адресов).

Не используете многоадресную рассылку или по какой-то конкретной причине вы выбрали широковещательную рассылку вместо многоадресной? Насколько я понимаю, с многоадресной рассылкой вы всегда будете знать, на каком интерфейсе принимаются пакеты, поскольку вы всегда привязываетесь к определенному интерфейсу при присоединении к группе многоадресной рассылки (особенно с IP4, где вы привязываетесь к интерфейсу через один из его IP-адресов).

Не используете многоадресную рассылку или по какой-то конкретной причине вы выбрали широковещательную рассылку вместо многоадресной? Насколько я понимаю, с многоадресной рассылкой вы всегда будете знать, на каком интерфейсе принимаются пакеты, поскольку вы всегда привязываетесь к определенному интерфейсу при присоединении к группе многоадресной рассылки (особенно с IP4, где вы привязываетесь к интерфейсу через один из его IP-адресов).

0
ответ дан 17 December 2019 в 04:51
поделиться

Чтобы повторить проблему, вам необходимо определить, на какой интерфейс были получены широковещательные UDP-пакеты.

  • Если вы привязываетесь к адресу с подстановочными знаками, вы получаете широковещательные рассылки, но нет способа определить на каком сетевом адресе был получен пакет.
  • Если вы привязываетесь к определенному интерфейсу, вы знаете, на какой адрес интерфейса вы получаете, но больше не получаете широковещательные рассылки (по крайней мере, в стеке TCP / IP Linux).

Как уже упоминалось другими, существуют сторонние библиотеки сырых сокетов для Java, такие как RockSaw или Jpcap , которые могут помочь вам определить адрес фактического интерфейса.

1
ответ дан 17 December 2019 в 04:51
поделиться

Не могу комментировать, поэтому добавляю это в качестве ответа.

Это интересно. Хотя мне любопытно, почему вы используете

byte[] addrBytes = InetAddress.getByName("126.5.6.7").getAddress();

, а не просто

byte[] addrBytes = {126, 5, 6, 7);

, или адреса интерфейсов попадают к вам как String?

0
ответ дан 17 December 2019 в 04:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: