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

Basically, I read in several places that socket.recv() will return everything that it can read, or an empty string signaling that the other side is closed (official documents do not even mention that it returns when the connection is closed. .. great!). This is all fine and a dandy for blocking sockets, since we know that recv() returned only when there is actually something to receive, so when it returns an empty string, it MUST mean that the other side is closed, right?

Alright, alright, but what happens when my socket is not blocked? I searched a bit (maybe not enough, who knows?) And cannot figure out how to say when the other side 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() with an empty string seems completely useless ... is that just me having this problem?

As a simple example, suppose my socket timeout is set to 1.2342342 (any non-negative number that you like here) seconds, and I call socket.recv(1024) , but the other side does not send anything during this second period 1.2342342. Calling recv() returns an empty string, and I don't know if the connection still stands or not ...

+41
python nonblocking sockets recv
May 25 '13 at
source share
4 answers

In the case of a non-blocking socket that has no data available, recv will throw a socket.error exception, and the exception value will have errno 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 bit different when you socket.settimeout(n) non-blocking behavior through a timeout with socket.settimeout(n) or socket.setblocking(False) . In this case, socket.error is raised, but in the case of a timeout, the accompanying exception value is always a string set to "timeout". So, to handle this case, you can:

 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 stated in the comments, this is also a more portable solution, since it does not depend on specific OS functions in order to put the socket in non-blocking mode.

See recv (2) and python socket for more details.

+52
May 25 '13 at 1:26
source share

When you use recv in connection with select , if the socket is ready to read, but there is no data to read, which means that the client has closed the connection.

Here is some code that handles this, also pay attention to the exception that is raised when recv is called a second time in the while loop. If there is nothing left to read this exception, this does not mean that the client has closed the connection:

 def listenToSockets(self): while True: changed_sockets = self.currentSockets ready_to_read, ready_to_write, in_error = select.select(changed_sockets, [], [], 0.1) for s in ready_to_read: if s == self.serverSocket: self.acceptNewConnection(s) else: self.readDataFromSocket(s) 

And the function that receives the data:

 def readDataFromSocket(self, socket): data = '' buffer = '' try: while True: data = socket.recv(4096) if not data: break buffer += data except error, (errorCode,message): # error 10035 is no data available, it is non-fatal if errorCode != 10035: print 'socket.error - ('+str(errorCode)+') ' + message if data: print 'received '+ buffer else: print 'disconnected' 
+4
May 25 '13 at 1:02
source share

It is simple: if recv() returns 0 bytes; You will not receive more data about this connection. Always. You can still send.

This means that your non-blocking socket should throw an exception (it may be system dependent) if the data is not available but the connection is still alive (the other end may send).

+4
May 25 '13 at 1:43
source share

To complete the existing answers, I suggest using select instead of non-blocking sockets . The fact is that non-blocking sockets complicate the material (with the possible exception of sending), so I would say that there is no reason to use them at all. If you regularly encounter a problem that your application is blocked while waiting for I / O, I will also consider the possibility of inputting IO in a separate thread in the background.

+2
May 25 '13 at 5:46
source share



All Articles