What Does Python's Socket.Recv() Return for Non-Blocking Sockets If No Data Is Received Until a Timeout Occurs

What does Python's socket.recv() return for non-blocking sockets if no data is received until a timeout occurs?

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:

import sys
import socket
import fcntl, os
import errno
from time import sleep

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1',9999))
fcntl.fcntl(s, fcntl.F_SETFL, os.O_NONBLOCK)

while True:
try:
msg = s.recv(4096)
except socket.error, e:
err = e.args[0]
if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
sleep(1)
print 'No data available'
continue
else:
# a "real" error occurred
print e
sys.exit(1)
else:
# got a message, do something :)

The situation is a little different in the case where you've enabled non-blocking behavior via a time out with socket.settimeout(n) or socket.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:

import sys
import socket
from time import sleep

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1',9999))
s.settimeout(2)

while True:
try:
msg = s.recv(4096)
except socket.timeout, e:
err = e.args[0]
# this next if/else is a bit redundant, but illustrates how the
# timeout exception is setup
if err == 'timed out':
sleep(1)
print 'recv timed out, retry later'
continue
else:
print e
sys.exit(1)
except socket.error, e:
# Something else happened, handle error, exit, etc.
print e
sys.exit(1)
else:
if len(msg) == 0:
print 'orderly shutdown on server end'
sys.exit(0)
else:
# got a message do something :)

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.

`sock.recv()` returns empty string when connection is dead on non-blocking socket

recv throws an exception if an error occurred. Closing a socket by the peer is no error, but is a normal behavior. In fact it is not even a full close: the peer only indicates that it will not send any more data, but it might still receive data. The TCP connection is only closed if both sides indicate that they will not send any more data, i.e. each side has send the FIN.

Why won't Python's socket.recv() return -1

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.



Related Topics



Leave a reply



Submit