Recv() с нулевой длиной?

Используя функцию recv() в C для чтения из сокета 'stream', может ли параметр len быть нулевым?

Функция recv() возвращает ноль для "удаленного подключения закрыта" и количество фактически прочитанных байтов при нормальной работе, поэтому звучит проблематично, если он должен читать нулевые байты.

P.S.
Да, я знаю, чтобы иметь дело с этим отдельно, и не добираться до этой ситуации, все же мне интересно, может ли функция справиться с этим, я не могу найти документацию об этом.

Ответ 1

Я считаю, что ответ "это зависит". Если он не указан стандартным (и, действительно, я считаю, что это не так), любая реализация может делать, как это угодно.

  • Это может привести к ошибке с EINVAL
  • Он может висеть
  • Он может вернуться 0 и продолжить
  • Он может печатать забавное сообщение и запускать игру изгоев (я понимаю, что gcc использовал это:)))

Фактически на моей реализации он возвращает 0 и продолжает. Чтобы проверить, не сработал или просто вернулся 0, вы можете проверить errno после вызова, поэтому он не так проблематичен, как вы думаете.

Ответ 2

Документация для recv в моей системе (Linux) говорит

Если в сокете нет сообщений, ожидающие сообщения ждут сообщения

и

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

На основе документации я ожидаю, что мой recv дождитесь сообщения, а затем удалит его (UDP) или оставьте в потоке (TCP).

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

Обновление. Тестирование показывает, что эта интерпретация документации является точной.

Сервер:

$ perl -MIO::Socket::INET -E'
   my $s = IO::Socket::INET->new(Listen => 1) or die $!;
   say $s->sockport;

   my $c = $s->accept or die $!;
   say "[".localtime."] connected";

   $c->recv(my $buf, 0) // die $!;
   say "[".localtime."] received";

   say <$c>;
'
39493
[Fri May 13 13:49:53 2011] connected
[Fri May 13 13:49:55 2011] received
foo

Клиент:

$ perl -MIO::Socket::INET -E'
   my $s = IO::Socket::INET->new(
      PeerAddr => "127.0.0.1",
      PeerPort => $ARGV[0],
   ) or die $!;
   sleep 2;
   say $s "foo";
' 39493

(Эти функции Perl - это просто тонкие интерфейсы для системных вызовов. Не стесняйтесь переписывать их на C.)

Ответ 3

Я почти уверен, что это undefined... глядя на Linux, он прошел весь путь до "драйвера" (т.е. tcp и т.д.), поэтому это может означать что-то, но опять же я не думаю этот смысл определен хорошо. Конечно, SuS ничего не говорит об этом.

Я думаю, что вам почти наверняка лучше не делать этого и использовать MSG_PEEK с 1 байтом или опросом() в зависимости от того, что вы хотите сделать.

Ответ 4

Страница POSIX о recv() на самом деле не совсем понятна. В ненормативной части ( "Применение приложения" ) говорится, что recv() в сокете эквивалентно read(), если флаги не указаны. На странице POSIX около read() говорится, что чтение из 0 байтов может проверять наличие ошибок; если нет ошибки или реализация не проверяет, ничего не происходит и возвращается 0.

Ответ 5

Я не думаю, что параметр длины может быть нулевым, так как даже пустую строку (сообщение) нужно завершить с помощью "\ 0".