Функция сокета recv () - PullRequest
       52

Функция сокета recv ()

0 голосов
/ 20 февраля 2019

В c ++, в ОС Windows, при вызове recv () для сокета TCP, если соединение с сокетом каким-либо образом закрыто, recv () вернется немедленно или зависнет?

Что будет в результате(сразу возвращается или зависает) в блокирующем и неблокирующем сокете?Я использую сокет версии 2.

Заранее спасибо.

Ответы [ 3 ]

0 голосов
/ 20 февраля 2019

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

Если сокет ориентирован на соединение, и удаленная сторона корректно отключила соединение, и все данные были получены, recv немедленно завершится сПолучено ноль байт.Если соединение было сброшено, произойдет сбой recv с ошибкой WSAECONNRESET.

Однако, поскольку я знаю, что Windows API не всегда работает в соответствии с документацией, я рекомендую проверить его.

0 голосов
/ 21 февраля 2019

recv() вернет 0 при изящном разъединении, то есть равноправный узел завершит свой конец соединения, и его стек сокетов отправит пакет FIN в ваш стек сокетов.Вы гарантированно получите этот результат немедленно, независимо от того, используете ли вы блокирующий или неблокирующий сокет.

recv() вернет -1 при любой другой ошибке, включая ненормальное соединениепотеря.Вам нужно использовать WSAGetLastError(), чтобы узнать, что на самом деле произошло.Для потерянного соединения в блокирующем сокете вы обычно получаете код ошибки, такой как WSAECONNRESET или WSAECONNABORTED.Для потерянного соединения в неблокирующем сокете возможно, что recv() может немедленно сообщить об ошибке WSAEWOULDBLOCK, а затем сообщить о фактической ошибке через некоторое время, возможно, через select() с исключением fd_set, илиасинхронное уведомление, в зависимости от того, как вы реализуете свою неблокирующую логику.

Однако, в любом случае, вы НЕ гарантированно получите результат сбоя в случае потери соединения в любой момент!МОЖЕТ занять некоторое время (секунды, минуты, может даже быть часами в редких случаях), прежде чем ОС сочтет, что соединение действительно потеряно, и делает недействительным соединение с сокетом.TCP предназначен для восстановления потерянных соединений, когда это возможно, поэтому он должен учитывать временные сбои в работе сети и тому подобное, поэтому существуют внутренние таймауты.Вы не видите этого в своем коде, это происходит в фоновом режиме.

Если вы не хотите ждать внутреннего истечения времени ожидания ОС, вы всегда можете использовать свой собственный тайм-аут в своем коде, например:через select(), setsocktopt(SO_RCVTIMEO), TCP keep-alives (setsockopt(SO_KEEPALIVE) или WSAIoCtl(SIO_KEEPALIVE_VALS)) и т. д. Вы можете все еще не получить сбой сразу , но вы получите его раньше, чем позже.

0 голосов
/ 20 февраля 2019

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

...