2016-04-13 1 views
2

Я пытался использовать сокеты UDP. На клиенте я устанавливаю определенный тайм-аут, и когда я вызываю recv(), я проверяю возвращаемое значение, и если оно меньше 0, я проверяю, является ли errno EAGAIN или EWOULDBLOCK. Если errno не является одним из этих 2, я пытаюсь восстановить соединение с сервером. Теперь мне нужно определить, закрыт ли другой конец соединения или нет. Кроме того, проверяя, что возвращаемое значение recv() равно «0», нужно ли проверять errno? Does recv() устанавливает errno, если другой конец сокета закрыт? Если нет, то почему errno не задан?Почему recv() не устанавливает errno, если закрыт другой конец сокета?

+4

Вопрос о «другом конце» сокета UDP напоминает запрос «другого конца» почтового ящика ... пакеты, протекающие через сокет UDP, могут поступать из (или переходить) к множеству разных адресатов. –

+0

Если вы хотите «подключения», то вам нужен TCP или, возможно, SCTP. –

ответ

8

UDP не имеет соединений, и поэтому вы не можете легко определить, закрыл ли другой конец разъема. Если вам нужны соединения, вы должны использовать TCP.

Однако часто принимает приемник отправляет ICMP-ответ при обращении к порту UDP, который не открыт; это может быть указано как возвращаемое значение от recv или send; в Linux это может случиться для любых сокетов UDP, а для BSD, похоже, это относится только к «подключенным» UDP-сокетам.

В любом случае, вы не можете вывести между любыми из

  • ICMP по отношению к отправителю фильтруется с помощью брандмауэра
  • UDP в сторону приемника фильтруется с помощью брандмауэра
  • UDP успешно доставлены в приемник

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


TCP очень похож на телефонный звонок, тогда как UDP больше похож на почтовые ящики. Если вы отправите письмо на несуществующий адрес, у которого нет почтового ящика, вы можете отправить через 2 недели с письмом, в котором говорится, что почта не может быть доставлена.

Если вы не получили письмо, то получатель получил его, почтовый человек украл его, он был измельчен на сортировочной машине или, возможно, собака съела письмо; единственный способ узнать, что он был фактически получен, будет заключаться в том, что получатель отправил другое письмо, подтверждающее получение.

+0

Спасибо Антти. В нашем проекте мы используем UDP, а на клиенте я использую вызов recv() с таймаутом. В каком-то угловом случае сервер умер, и в наших системах есть агент мониторинга, который будет отслеживать процесс, и если какой-либо процесс замирает, он перезапустит процесс. Поскольку я проверяю только, если возвращаемое значение os recv() меньше 0, я слушаю старый сокет, и хотя сервер запускается заново, я не могу получить сообщения. Можете ли вы предложить любую идею, как исправить. – kadina

+0

@ kadina: Это звучит очень странно. Поскольку UDP не является соединением, прослушивающий UDP-сокет должен забрать все, что отправлено на его IP-адрес и порт. Вы уверены, что другая сторона не просто забыла отправить вам? –

+0

@kadina: например, демон syslog, прослушивающий сообщения syslog UDP, не нуждается в повторном открытии своего сокета. Он просто продолжает получать сообщения. –

Смежные вопросы