Предполагая, что вы используете стандартный модуль сокета, вы должны перехватить исключение socket.error: (32, 'Broken pipe')
(не IOError, как предлагали другие). Это будет затронуто в случае, который вы описали, то есть отправка / запись в сокет, для которого удаленная сторона отключилась.
import socket, errno, time
# setup socket to listen for incoming connections
s = socket.socket()
s.bind(('localhost', 1234))
s.listen(1)
remote, address = s.accept()
print "Got connection from: ", address
while 1:
try:
remote.send("message to peer\n")
time.sleep(1)
except socket.error, e:
if isinstance(e.args, tuple):
print "errno is %d" % e[0]
if e[0] == errno.EPIPE:
# remote peer disconnected
print "Detected remote disconnect"
else:
# determine and handle different error
pass
else:
print "socket error ", e
remote.close()
break
except IOError, e:
# Hmmm, Can IOError actually be raised by the socket module?
print "Got IOError: ", e
break
Обратите внимание, что это исключение не всегда будет вызываться при первой записи в закрытый сокет - чаще при второй записи (если только число байтов, записанных в первой записи, не превышает размер буфера сокета). Вам следует помнить об этом, если ваше приложение считает, что удаленный конец получил данные с первой записи, когда он, возможно, уже отключился.
Вы можете уменьшить (но не полностью устранить) это, используя select.select()
(или poll
). Проверьте, готовы ли данные для чтения с однорангового узла, прежде чем пытаться выполнить запись. Если select
сообщает, что есть данные, доступные для чтения из однорангового сокета, прочитайте их, используя socket.recv()
. Если это возвращает пустую строку, удаленный узел закрыл соединение. Поскольку здесь все еще есть состояние гонки, вам все равно нужно поймать и обработать исключение.
Twisted отлично подходит для такого рода вещей, однако, похоже, вы уже написали немало кода.