Краткий ответ:
используйте неблокирующую функцию recv () или блокирующую функцию recv () / select () с очень
короткий тайм-аут.
Длинный ответ:
Способ обработки соединений с сокетами - читать или писать по мере необходимости и быть готовым к обработке ошибок соединения.
TCP различает 3 формы «сбрасывания» соединения: таймаут, сброс, закрытие.
Из них тайм-аут на самом деле не может быть обнаружен, TCP может только сказать вам, что время еще не истекло. Но даже если бы он сказал вам об этом, время может истечь сразу после.
Также помните, что при использовании shutdown () вы или ваш коллега (другой конец соединения) можете закрыть только входящий поток байтов и сохранить работающий исходящий поток байтов, или закрыть исходящий поток и сохранить работающий входящий. .
Строго говоря, вы хотите проверить, закрыт ли поток чтения, закрыт ли поток записи или закрыты оба.
Даже если соединение было «разорвано», вы все равно сможете прочитать любые данные, которые все еще находятся в сетевом буфере. Только после того, как буфер опустеет, вы получите отключение от recv ().
Проверка разрыва соединения - это все равно, что спросить "что я получу после прочтения всех данных, которые в данный момент буферизируются?" Чтобы это выяснить, вам просто нужно прочитать все данные, которые в данный момент находятся в буфере.
Я вижу, как «чтение всех буферизованных данных», чтобы добраться до конца, может быть проблемой для некоторых людей, которые до сих пор считают recv () блокирующей функцией. При блокировке recv () блокируется «проверка» на чтение, когда буфер уже пуст, что лишает цели «проверки».
По моему мнению, любая функция, которая задокументирована так, чтобы потенциально блокировать весь процесс на неопределенный срок, является недостатком проекта, но я предполагаю, что она все еще существует по историческим причинам, начиная с использования сокета, так же как обычный дескриптор файла был отличной идеей.
Что вы можете сделать:
- установить сокет в неблокирующий режим, но затем вы получите системно-зависимую ошибку, указывающую, что буфер приема пуст или буфер отправки заполнен
- придерживаться режима блокировки, но установить очень короткий тайм-аут сокета. Это позволит вам «пинговать» или «проверять» сокет с помощью recv (), в значительной степени то, что вы хотите сделать
- используйте вызов select () или асинхронный модуль с очень коротким тайм-аутом. Отчет об ошибках по-прежнему зависит от системы.
Что касается проблемы записи, то поддержание пустых буферов чтения в значительной степени покрывает это. Вы обнаружите, что соединение «сброшено» после неблокирующей попытки чтения, и вы можете прекратить отправку чего-либо после того, как чтение вернет закрытый канал.
Полагаю, единственный способ убедиться, что ваши отправленные данные достигли другого конца (и еще не находится в буфере отправки), это:
- получите правильный ответ в том же сокете для точного отправленного вами сообщения. В основном вы используете протокол более высокого уровня для подтверждения.
- успешно выполнить shutdow () и close () на сокете
Python-сокет howto сообщает, что send () вернет 0 байт, записанных, если канал закрыт. Вы можете использовать неблокирующую или timeout socket.send (), и если она возвращает 0, вы больше не можете отправлять данные в этот сокет. Но если он возвращает ненулевое значение, вы уже отправили что-то, удачи вам:)
Также здесь я не рассматривал данные сокетов OOB (out-of-band) здесь как средство для решения вашей проблемы, но я думаю, что OOB был не тем, что вы имели в виду.