Отключите и снова подключите подключенный разъем датаграммы - PullRequest
3 голосов
/ 26 мая 2009

Я пытаюсь создать итеративный сервер на основе сокетов дейтаграмм (UDP). Он вызывает connect для первого клиента, который он получает при первом вызове recvfrom () (да, я знаю, что это не реальное соединение). После обслуживания этого клиента я отсоединяю сокет UDP (вызывая соединение с AF_UNSPEC) Затем я вызываю recvfrom (), чтобы получить первый пакет от следующего клиента.

Теперь проблема в том, что вызов recvfrom () во второй итерации цикла возвращает 0. Мои клиенты никогда не отправляют пустые пакеты, так что может происходить.

Это то, что я делаю (псевдокод):

s = socket(PF_INET, SOCK_DGRAM, 0)

bind(s)

for(;;)
{
  recvfrom(s, header, &client_address)  // get first packet from client
  connect(s,client_address)  // connect to this client
  serve_client(s);
  connect(s, AF_UNSPEC); // disconnect, ready to serve next client
}

РЕДАКТИРОВАТЬ: Я обнаружил ошибку в моем клиенте случайно отправив пустой пакет. Теперь моя проблема заключается в том, чтобы заставить клиента ждать обслуживания, а не отправлять запрос в никуда (сервер подключен к другому клиенту и еще не обслуживает другого клиента).

Ответы [ 3 ]

3 голосов
/ 26 мая 2009

connect () действительно совершенно не нужен для SOCK_DGRAM.

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

ИСПРАВЛЕНИЕ: да, по-видимому, оно останавливает получение пакетов от других хостов. Но делать это на сервере немного глупо, потому что любые другие клиенты будут заблокированы, пока вы подключены () к одному. Также вам все равно нужно будет ловить "мякину", которая плавает вокруг. Вероятно, существуют некоторые условия состязания, связанные с connect () в сокете DGRAM - что произойдет, если вы вызываете connect и пакеты из других хостов уже находятся в буфере?

Кроме того, 0 является допустимым возвращаемым значением из recvfrom (), поскольку пустые (без данных) пакеты являются действительными и могут существовать (действительно, люди часто их используют). Поэтому вы не можете проверить, удалось ли что-то таким образом.

По всей вероятности, пакет с нулевым байтом уже был в очереди.

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

Приложения UDP ДОЛЖНЫ быть в состоянии распознавать "случайные" пакеты и отбрасывать их; они рано или поздно появятся.

0 голосов
/ 02 июня 2015

Просто поправка на случай, если кто-нибудь наткнется на это, как я. Для отключения connect () должен быть вызван с элементом sa_family sockaddr, установленным в AF_UNSPEC. Не просто передал AF_UNSPEC.

0 голосов
/ 26 мая 2009

man connect:

...
If the initiating socket is not connection-mode, then connect()
shall set the socket’s peer address, and no connection is made.
For SOCK_DGRAM sockets, the peer address identifies where all
datagrams are sent on subsequent send() functions, and limits
the remote sender for subsequent recv() functions. If address
is a null address for the protocol,  the  socket’s  peer  address
shall be reset.
...
...