Работает ли recv(...) таким образом?

Я устанавливаю таймаут для сокета, используя SO_RCVTIMEO до 10 секунд. Этот вопрос относится к потоковому сокету (TCP). Когда я звоню recv(...) из того, что я могу почерпнуть из справочных страниц, вот что я ожидаю:

  1. Если удаленное соединение закрывает соединение, оно немедленно возвращает 0 независимо от времени ожидания.
  2. Если время ожидания истекло и данные не были получены, то мы получаем -1 и возвращаемое errno из EAGAIN или же EWOULDBLOCK,
  3. Если в сокете возникает ошибка, она сразу возвращается с -1, а затем errno настроен правильно.
  4. Если данные становятся доступными, сокет ждет, пока не истечет время ожидания, прежде чем вернуться. На этот раз он вернется через 10 секунд с общим количеством полученных байтов.

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

Спасибо! Brett

2 ответа

Решение
  1. Правильный.
  2. Есть две разные спецификации (к сожалению, я не могу проверить в настоящее время)
    2,1 ETIMEOUT будет возвращен. (EAGAIN или же EWOULDBLOCK возвращаются на неблокирующих сокетах, если данные сразу не доступны.) http://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html
    2,2 EAGAIN или же EWOULDBLOCK будет возвращено для обеих возможностей, упомянутых в 2.1 http://man7.org/linux/man-pages/man2/recvmsg.2.html
  3. Правильный.
  4. Если был прочитан хотя бы 1 байт, сокет может вернуться в любое время, даже если будет прочитано меньше, тогда сообщается, и время ожидания еще не истекло.

Довольно много.

Есть одна оговорка: если вы установите MSG_WAITALLПо крайней мере одна реализация (FreeBSD) запускает таймер заново каждый раз, когда поступают некоторые данные. Например, если вы попросите recv 8192 байта и один байт прибывает, таймер сбрасывается. Если в течение 10 секунд поступит другой байт, таймер снова сбрасывается. Так что, если байты текут один раз в 5 секунд, вы будете ждать (8191 * 5) = 40955 секунд = более чем за 11 часов до recv наконец возвращает 8192. (Если до EOF поступает недостаточно байтов, recv не удается с EAGAIN.)

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

Другие вопросы по тегам