Python не обнаруживает закрытый сокет до второй отправки - PullRequest
16 голосов
/ 04 февраля 2011

Когда я закрываю сокет на одном конце соединения, другой конец получает ошибку во второй раз, когда отправляет данные, но не в первый раз:

import socket

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("localhost", 12345))
server.listen(1)

client = socket.create_connection(("localhost",12345))
sock, addr = server.accept()
sock.close()

client.sendall("Hello World!")    # no error
client.sendall("Goodbye World!")  # error happens here

Я пытался установить TCP_NODELAY, используя send вместо sendall, проверяя fileno(), я не могу найти способ получить первое посылку, чтобы выдать ошибку или даже обнаружить впоследствии, что она не удалась , РЕДАКТИРОВАТЬ: вызов sock.shutdown до sock.close не помогает. РЕДАКТИРОВАНИЕ # 2: даже добавление time.sleep после закрытия и перед записью не имеет значения. РЕДАКТИРОВАТЬ # 3: проверка количества байтов, возвращаемых send, не помогает, поскольку всегда возвращает количество байтов в сообщении.

Таким образом, единственное решение, которое я могу придумать, если я хочу обнаружить ошибки, - это следовать каждому sendall с client.sendall(""), что вызовет ошибку. Но это кажется хакерским. Я использую Linux 2.6.x, поэтому, даже если бы решение работало только для этой ОС, я был бы счастлив.

Ответы [ 2 ]

13 голосов
/ 04 февраля 2011

Это ожидается, и как реализованы API-интерфейсы TCP / IP (так что это похоже почти во всех языках и во всех операционных системах)

Коротко говоря, вы ничего не можете сделать, чтобы гарантировать, чтоВызов send () возвращает ошибку напрямую, если этот вызов send () каким-то образом не может доставить данные на другой конец.вызовы send / write просто доставляют данные в стек TCP, и это зависит от стека TCP, чтобы доставить его, когда это возможно.

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

Однако - если вы читаете () из сокетавы можете получать уведомления сразу же, когда возникает ошибка или когда другой конец закрывает сокет - вам обычно нужно делать это в какой-либо форме цикла событий мультиплексирования (то есть с использованием select / poll или некоторого другого средства мультиплексирования ввода-вывода).

Просто отметьте, что вы не можете читать () из сокета, чтобы узнать, была ли успешной самая последняя отправка / запись. Вот несколько случаев, почему (но это случаи, о которых никто не задумывается, всегда вас заводит)

  • несколько вызовов write () были буферизованы из-за перегрузки сети или из-за закрытия окна tcp (возможно, медленного чтенияr) и затем другой конец закрывает сокет, или возникает ошибка жесткого диска, поэтому вы не можете определить, была ли последняя запись, которая не прошла, или запись, которую вы сделали 30 секунд назад.
  • Ошибка сети или брандмауэр молча отбрасывает ваши пакеты (ответы ICMP не генерируются). Вам придется подождать, пока TCP не истечет время ожидания соединения, чтобы получить ошибку, которая может составлять много секунд, обычно несколько минут.
  • TCPзанят повторной передачей, когда вы звоните send - возможно, эти повторные передачи вызывают ошибку (на самом деле то же, что и в первом случае)
1 голос
/ 04 февраля 2011

Согласно документам , попробуйте позвонить sock.shutdown() до вызова sock.close().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...