Python: Non-blocking socket or Asynchronos I/O

Tu Hoang picture Tu Hoang · Jun 16, 2011 · Viewed 27.4k times · Source

I am new to Python and currently have to write a python socket to be run as a script that communicates with a device over TCP/IP (a weather station).
The device acts as the Server Side (listening over IP:PORT, accepting connection, receiving request, transferring data).
I only need to send one message, receive the answer and then peacefully and nicely shutdown and close the socket.

try:
    comSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error, msg:
    sys.stderr.write("[ERROR] %s\n" % msg[1])
    sys.exit(1)

try:
   comSocket.connect((''))
except socket.error, msg:
   sys.stderr.write("[ERROR] %s\n" % msg[1])
   sys.exit(2)

comSocket.send('\r')
comSocket.recv(128)
comSocket.send('\r')
comSocket.recv(128)
comSocket.send('\r\r')
comSocket.recv(128)

comSocket.send('1I\r\r3I\r\r4I\r\r13I\r\r5I\r\r8I\r\r7I\r\r9I\r\r')

rawData = comSocket.recv(512)

comSocket.shutdown(1)
comSocket.close()

The problem I'm having is:
The communication channel is unreliable, the device is slow. So, sometimes the device response with message of length 0 (just an ACK), the my code will freeze and wait for response forever.
This piece of code contains the portion that involves SOCKET, the whole code will be run under CRON so freezing is not a desirable behavior.

My question is:
What would be the best way in Python to handle that behavior, so that the code doesn't freeze and wait forever but will attempt to move on to the next send (or such).

Answer

Felipe Cruz picture Felipe Cruz · Jun 16, 2011

You can try a timeout approach, like Russel code or you can use a non-blocking socket, as shown in the code below. It will never block at socket.recv and you can use it inside a loop to retry as many times you want. This way your program will not hang at timeout. This way, you can test if data is available and if not, you can do other things and try again later.

socket.setblocking(0)
while (retry_condition):
    try:
        data = socket.recv(512)
    except socket.error:
        '''no data yet..'''