如何处理python中的破pipe(SIGPIPE)?

我用python编写了一个简单的multithreading游戏服务器,为每个客户端连接创build一个新的线程。 我发现,每隔一段时间,服务器将崩溃,因为pipe道损坏/ SIGPIPE错误。 我很确定,当程序试图向不再存在的客户端发送响应时,它正在发生。

什么是处理这个问题的好方法? 我的首选解决scheme将简单地closures到客户端的服务器端连接,继续前进,而不是退出整个程序。

PS: 这个问题/答案以通用的方式处理问题; 我应该如何具体解决它?

阅读try:语句。

try: # do something except socket.error, e: # A socket error except IOError, e: if e.errno == errno.EPIPE: # EPIPE error else: # Other error 

假设你正在使用标准套接字模块,你应该捕获socket.error: (32, 'Broken pipe')exception(不像其他人所build议的那样是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 

请注意,在第一次写入closures的套接字时,并不总是会引发此exception,通常是第二次写入(除非第一次写入的字节数大于套接字的缓冲区大小)。 如果应用程序认为远端从第一次写入的数据可能已经断开连接,则需要记住这一点。

你可以通过使用select.select() (或者poll )来减less这个事件的发生(但是不能完全消除)。 在尝试写入之前检查是否准备好从对等端读取数据。 如果select报告有数据可用来从对等套接字读取,请使用socket.recv()读取它。 如果这返回一个空string,远程对等closures了连接。 因为这里仍然存在竞争条件,你仍然需要捕捉并处理exception情况。

扭曲对于这类事情来说是很好的,但是,听起来好像你已经写了一些代码。

SIGPIPE (虽然我想也许你的意思是EPIPE ?)在套接字上发生,当你closures一个套接字,然后发送数据给它。 简单的解决scheme是在尝试发送数据之前不要closures套接字。 这也可能发生在pipe道上,但听起来不像你正在经历的那样,因为它是一个networking服务器。

您也可以在每个线程的顶级处理程序中应用捕获exception的创可贴。

当然,如果你使用Twisted而不是为每个客户端连接产生一个新的线程,你可能不会有这个问题。 如果多个线程正在处理相同的I / O通道,那么确实很难(也许根本不可能,取决于您的应用程序)来获得closures和写入操作的顺序。

我面对同样的问题。 但我下次提交相同的代码,它只是工作。 第一次爆发:

 $ packet_write_wait: Connection to 10.. port 22: Broken pipe 

第二次工作:

 [1] Done nohup python -u add_asc_dec.py > add2.log 2>&1 

我猜可能是因为当前的服务器环境。

我的答案非常接近S.Lott's,除非我更特别:

 try: # do something except IOError, e: # ooops, check the attributes of e to see precisely what happened. if e.errno != 23: # I don't know how to handle this raise 

其中“23”是您从EPIPE获得的错误号码。 这样您就不会尝试处理权限错误或其他任何您不具备的function。