Обрабатывать недоступные UDP-порты с помощью Java-сокетов

#java #networking #udp #datagram

#java #сеть #udp #дейтаграмма

Вопрос:

Я использую Java DatagramSocket для потоковой передачи данных нескольким разным клиентам. Поскольку я сам обрабатываю список зарегистрированных в данный момент клиентов, я только привязываю сокет к порту сервера и не подключаюсь ни к какому конкретному клиенту.

Однако, не используя connect(), я теряю способность DatagramSocket реагировать на ICMP-уведомления о недоступном порту, которые отправляются, если один из клиентов умирает и не получает возможности должным образом отменить регистрацию на сервере.

Есть ли какой-либо способ вернуть это поведение? Я думал использовать один DatagramSocket для каждого клиента, но это, похоже, неосуществимо, поскольку все они должны быть привязаны к одному и тому же порту на сервере (насколько я знаю, невозможно в UDP).

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

Ответ №1:

Если вам нужны надежные соединения «точка-точка», я бы использовал TCP.

Однако, если вам нужен UDP, я бы посоветовал вашим клиентам отправлять сообщения, чтобы издатель мог отключать подписчиков, которые прекращают отправку. Я предполагаю, что вам не нужно, чтобы соединение было надежным, но оно все равно может стоить подписчикам отправки пакетов обратно издателю.

Комментарии:

1. Мне не нужна надежная связь, но я также не хочу заливать невинных пользователей (для них) бессмысленным трафиком 😉 Я, вероятно, выберу опцию heartbeat.

2. Если у вас есть интеллектуальные маршрутизаторы, они будут перенаправлять UDP-трафик только на серверы, которые прослушивают этот трафик. Это приводит к пустой трате ресурсов на сервере.

3. Я беспокоюсь не о сервере (он получает только очень маленькие и случайные запросы от новых пользователей), а о пользователях, которые могут получить ненужные данные. Мое приложение выполняет потоковую передачу звука, и клиент может аварийно завершиться или быть принудительно закрыт без надлежащей отмены регистрации с сервера. Я не понимаю, как маршрутизатор между мной и пользователем мог отличить этот случай от того, когда пользователь просто продолжает прослушивать (за исключением того, что маршрутизатор является брандмауэром с отслеживанием состояния, который учитывает ICMP-сообщения с хоста пользователя).

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

5. Я знаю, как работают UDP и сокеты. Мой сервер отправляет данные в список IP-адресов / портов; этот список обновляется, когда клиент отправляет пакет «подключиться» или «отключить». Однако клиент может быть внезапно отключен, и пакет «disconnect» никогда не достигнет моего сервера. IP, на котором был запущен клиент, получит много ненужных пакетов; я хочу избежать этого.

Ответ №2:

Причина, по которой это выдается только подключенными UDP-сокетами, заключается в том, что именно так это работает на уровне ‘C’, и причина этого в том, что, будучи асинхронным, нет другого способа определить, какой целевой адрес вызвал это, потому что все, что у вас есть на уровне ‘C’, — это errno , а не содержимое самого ICMP-сообщения. Итак, чтобы «вернуть поведение», вам действительно понадобится сокет для каждого подключенного клиента. Если это непрактично, вам просто придется полагаться на наличие или отсутствие учетных записей приложений.