Отключите и повторно подключите подключенный сокет дейтаграммы

StackOverflow https://stackoverflow.com/questions/911359

Вопрос

Я пытаюсь создать итеративный сервер на основе сокетов дейтаграмм (UDP).Он вызывает connect к первому клиенту, который он получает от первого вызова recvfrom() (да, я знаю, что это не настоящее connect).После обслуживания этого клиента я отключаю сокет UDP (вызываю connect с помощью 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
}

Редактировать:Я обнаружил ошибку в том, что мой клиент случайно отправил пустой пакет.Теперь моя проблема заключается в том, как заставить клиента ждать обслуживания вместо того, чтобы отправлять запрос в никуда (сервер подключен к другому клиенту и пока не обслуживает ни одного другого клиента).

Это было полезно?

Решение

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

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

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

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

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

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

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

Другие советы

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.
...

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top