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)
) и т. д. Вы можете все еще не получить сбой сразу , но вы получите его раньше, чем позже.