Basically, I've read in several places that socket.recv()
will return whatever it can read, or an empty string signalling that the other side has shut down (the official docs don't even mention what it returns when the connection is shut down... great!). This is all fine and dandy for blocking sockets, since we know that recv()
only returns when there actually is something to receive, so when it returns an empty string, it MUST mean the other side has closed the connection, right?
Okay, fine, but what happens when my socket is non-blocking?? I have searched a bit (maybe not enough, who knows?) and can't figure out how to tell when the other side has closed the connection using a non-blocking socket. There seems to be no method or attribute that tells us this, and comparing the return value of recv()
to the empty string seems absolutely useless... is it just me having this problem?
As a simple example, let's say my socket's timeout is set to 1.2342342 (whatever non-negative number you like here) seconds and I call socket.recv(1024)
, but the other side doesn't send anything during that 1.2342342 second period. The recv()
call will return an empty string and I have no clue as to whether the connection is still standing or not...
It is simple: if
recv()
returns 0 bytes; you will not receive any more data on this connection. Ever. You still might be able to send.It means that your non-blocking socket have to raise an exception (it might be system-dependent) if no data is available but the connection is still alive (the other end may send).
Just to complete the existing answers, I'd suggest using select instead of nonblocking sockets. The point is that nonblocking sockets complicate stuff (except perhaps sending), so I'd say there is no reason to use them at all. If you regularly have the problem that your app is blocked waiting for IO, I would also consider doing the IO in a separate thread in the background.
In the case of a non blocking socket that has no data available, recv will throw the socket.error exception and the value of the exception will have the errno of either EAGAIN or EWOULDBLOCK. Example:
The situation is a little different in the case where you've enabled non-blocking behavior via a time out with
socket.settimeout(n)
orsocket.setblocking(False)
. In this case a socket.error is stil raised, but in the case of a time out, the accompanying value of the exception is always a string set to 'timed out'. So, to handle this case you can do:As indicated in the comments, this is also a more portable solution since it doesn't depend on OS specific functionality to put the socket into non-blockng mode.
See recv(2) and python socket for more details.
When you use
recv
in connection withselect
if the socket is ready to be read from but there is no data to read that means the client has closed the connection.Here is some code that handles this, also note the exception that is thrown when
recv
is called a second time in the while loop. If there is nothing left to read this exception will be thrown it doesn't mean the client has closed the connection :And the function that receives the data :