我在python中编写了一个简单的多线程游戏服务器,为每个客户端连接创建一个新线程.我发现时不时,服务器会因为管道损坏/ SIGPIPE错误而崩溃.当程序试图将响应发送回不再存在的客户端时,我非常确定它正在发生.
处理这个问题的好方法是什么?我的首选解决方案只是关闭与客户端的服务器端连接并继续,而不是退出整个程序.
PS:这个问题/答案以一般方式处理问题; 具体应该如何解决?
假设您正在使用标准套接字模块,您应该捕获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()
.如果返回空字符串,则远程对等方已关闭连接.因为这里仍然存在竞争条件,所以您仍然需要捕获并处理异常.
扭曲对于这种事情是很好的,但是,听起来你已经编写了相当多的代码.
阅读try:语句.
try: # do something except socket.error, e: # A socket error except IOError, e: if e.errno == errno.EPIPE: # EPIPE error else: # Other error