Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle a broken pipe (SIGPIPE) in python?

I've written a simple multi-threaded game server in python that creates a new thread for each client connection. I'm finding that every now and then, the server will crash because of a broken-pipe/SIGPIPE error. I'm pretty sure it is happening when the program tries to send a response back to a client that is no longer present.

What is a good way to deal with this? My preferred resolution would simply close the server-side connection to the client and move on, rather than exit the entire program.

PS: This question/answer deals with the problem in a generic way; how specifically should I solve it?

like image 230
Adam Plumb Avatar asked Oct 07 '08 19:10

Adam Plumb


People also ask

How does Python handle broken pipe error?

Properly catching IOError to avoid Broken pipe error As a Broken pipe error is an IOError error, we can place a try/catch block in order to catch it, as shown in the following snippet of code: Syntax: import sys, errno.

How do you handle a SIGPIPE?

You generally want to ignore the SIGPIPE and handle the error directly in your code. This is because signal handlers in C have many restrictions on what they can do. The most portable way to do this is to set the SIGPIPE handler to SIG_IGN . This will prevent any socket or pipe write from causing a SIGPIPE signal.

How do you fix a broken pipe error?

This kind of error can easily be fixed with a command like “sudo apt install –f”. On rare occasions, you may have experienced a broken pipe error. A pipe in Linux / Unix connects two processes, one of them has read-end of the file and the other one has the write-end of the file.

What causes a broken pipe error Python?

Python interpreter is not capable enough to ignore SIGPIPE by default, instead, it converts this signal into an exception and raises an error which is known as IOError(INPUT/OUTPUT error) also know as 'Error 32' or Broken Pipe Error.


1 Answers

Assuming that you are using the standard socket module, you should be catching the socket.error: (32, 'Broken pipe') exception (not IOError as others have suggested). This will be raised in the case that you've described, i.e. sending/writing to a socket for which the remote side has disconnected.

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 

Note that this exception will not always be raised on the first write to a closed socket - more usually the second write (unless the number of bytes written in the first write is larger than the socket's buffer size). You need to keep this in mind in case your application thinks that the remote end received the data from the first write when it may have already disconnected.

You can reduce the incidence (but not entirely eliminate) of this by using select.select() (or poll). Check for data ready to read from the peer before attempting a write. If select reports that there is data available to read from the peer socket, read it using socket.recv(). If this returns an empty string, the remote peer has closed the connection. Because there is still a race condition here, you'll still need to catch and handle the exception.

Twisted is great for this sort of thing, however, it sounds like you've already written a fair bit of code.

like image 186
mhawke Avatar answered Sep 28 '22 09:09

mhawke