Reputation: 2888
If I close a server socket while in a s.recv_into()
loop from a client, I keep getting 0 from recv_into()
infinitely.
As I understand, the only way to know a socket is closed was not through the Python socket mechanism itself, but using select / poll / etc.
What's the rational of not returning -1 when the socket is closed by the other side? Why can't I properly differentiate "no data currently" from "no one there anymore"?
EDIT:
Perhaps the correct question is - why is no exception thrown when using recv()
, if the other side terminated the connection?
Upvotes: 0
Views: 842
Reputation: 56587
If I close a server socket while in a
s.recv_into()
loop from a client, I keep getting 0 fromrecv_into()
infinitely.
Yes, as expected. A closed connection is indicated by 0, not -1.
As I understand, the only way to know a socket is closed was not through the Python socket mechanism itself, but using select / poll / etc.
No, that's not true. Simply calling recv
in a non-blocking mode will do the job without involving any selector mechanism. In a non-blocking mode the "no data yet" state will be indicated by an appropriate exception (note that you have to inspect that exception, it's not the only case when recv
throws).
However this doesn't mean that the peer is still alive (the default TCP timeout is 15 minutes AFAIK). This cannot be reliably detected. The best you can do is to implement some pinging protocol over the wire.
What's the rational of not returning -1 when the socket is closed by the other side?
For syscalls (such as recv
) the -1 return code is (typically) reserved for errors. However Python translates these into exceptions (and so AFAIK you will never get -1 in Python).
Anyway 0 is not an error. It's an information that the other side closed the connection. Perhaps this is a completely valid situation, there's no way for Python (or any other language) to know that.
Upvotes: 1
Reputation: 134066
The recv_into
is just a wrapper of the C system call by name recv
. The return value of 0
is not an erroneous condition!
From Linux manuals, recv(2)
:
RETURN VALUE
These calls return the number of bytes received, or -1 if an error occurred. In the event of an error, errno is set to indicate the error.
When a stream socket peer has performed an orderly shutdown, the return value will be 0 (the traditional "end-of-file" return).
Datagram sockets in various domains (e.g., the UNIX and Internet domains) permit zero-length datagrams. When such a datagram is received, the return value is 0.
The value 0 may also be returned if the requested number of bytes to receive from a stream socket was 0.
For error cases, Python will not return -1
, instead it will raise an appropriate exception.
For a stream sockets you must break the loop whenever recv_*
returns a value that indicates that 0 bytes were received. There is no point for checking -1
, but in case you do want to be extra certain, you can naturally use while sock.recv_into(....) > 0:
or similar.
The various read
calls in Python work in similar fashion.
Upvotes: 1