2017-02-03 19 views
2

Исходя из предположения, что протокол UDP является протоколом без установления соединения, я предположил, что хост вверх или вниз будет неактуальным.«Connected» UDP-разъем получает порт ICMP Unreachable

Однако теперь, когда я тестирую, я обнаружил, что когда я подключил свой клиентский сокет UDP, write к этому сокету возвращает ошибку, потому что сервер отправил сообщение об ошибке ICMP Port Unreachable.

цель «соединительном» порт UDP (по Stevens Unix Сетевое программирование) состоит в основном кэши запись из таблицы маршрутизации, а не создавать новый для каждого пакета, который должен имеют преимущества в производительности.

Однако этот ICMP-пакет вызывает у меня потерянный клиентский сокет, что очень раздражает.

Может ли кто-нибудь пролить свет на то, почему это может быть? Существуют ли какие-либо известные способы обхода?

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

EDIT

В целом это не представляется возможным, и фиксируя код является единственным способом сделать это.

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

+0

Тем не менее, я не уверен, что понимаю ваш вопрос. Вы попытались подключить сокет к конечной точке, которая недоступна, и получили ошибку ICMP. Почему вы не ошиблись, если попытаетесь «написать»? – Alnitak

+0

Потому что это * connectionless * - действительно, если бы я не подключился, я бы не получил эту ошибку. Не вводите в заблуждение связанное слово, просто потому, что это не то, что это означает в контексте датаграммы. Как я уже сказал, Стивенс даже кажется загадочным. – robert

+0

Давайте продолжим обсуждение в чате (http://chat.stackoverflow.com/rooms/134756/discussion-between-alnitak-and-robert). – Alnitak

ответ

3

Хотя ваш разъем UDP не является строго «подключенным», вызов connect() создает локальное «состояние» для этого сокета.

Это состояние не только позволяет системе кэшировать текущую запись маршрутизации для адресата, но также означает, что для всех последующих операций вывода не требуется указать адресата - они будут использовать тот, который указан в вызове connect(). Это также гарантирует, что ядро ​​выкинет входящие пакеты, предназначенные для вашего сокета, которые не поступают из «подключенной» стороны.

Это подключенное состояние также позволяет ядру доставлять в приложение ошибки, связанные с этим сокетом (с сигналом через ICMP) - не подключенные разъемы не получают их - они «срабатывают и забываются».

В случае кода log4j, который вы указали мне в автономном режиме, проблема оказывается полностью в коде пространства пользователя. Log4j UDPAppender просто в одностороннем порядке выбрасывает сокет, когда он получает код IOException по вызову write и не предоставляет никаких средств для обнаружения этого условия, чтобы вы могли его исправить.

+0

Спасибо за вашу помощь и понимание экспертов. – robert

-2

Ну, UDP находится в верхней части IP. И сообщение, которое вы получаете, происходит из этого слоя. См https://en.wikipedia.org/wiki/User_Datagram_Protocol и https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol

Так что это соединение менее в том смысле, что вы не имеете постоянный туннель, так что это не будет гарантировать, что ваши пакеты поступают в порядке, и прочее. Или вы не обязательно сразу узнаете, есть ли ошибка.

Но вы все равно должны иметь возможность подключиться к чему-то, для начала. Это происходит только на более низком уровне.

Но ядро ​​по-прежнему будет отслеживать сокет, поэтому оно может уведомить вас о полученных ICMP-пакетах, скажем, от маршрутизаторов. Дело в том, что ICMP - это слой ниже.

ОБНОВЛЕНИЕ: Кстати, я думаю, у вас может возникнуть проблема по-другому. Ваш маршрутизатор или все, что находится между ними, может просто игнорировать тот факт, что он не знает, куда до подключиться к , пересылать пакет и просто молча отбрасывать пакет, вместо того, чтобы отвечать сообщением об ошибке ICMP.

+0

Спасибо за ваше понимание Дэна. На данный момент я действительно немного поработал над этой проблемой, и похоже, что нам придется переписать код. Проверьте это, как описано, как «подключенное» состояние применяется к UDP. Http://www.masterraghu.com/subjects/np/introduction/unix_network_programming_v1.3/ch08lev1sec11.html – robert

+0

Вам не нужно подключать UDP-сокет , Ваш последний абзац не имеет смысла. – EJP

+1

Хорошо, позвольте мне немного перефразировать ... :) – Dan