11

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).

pradyunsg
  • 18,287
  • 11
  • 43
  • 96
Tu Hoang
  • 4,622
  • 13
  • 35
  • 48
  • 5
    You should have a look at the [Twisted](http://twistedmatrix.com/) library for Python. It is a framework for asynchronous networking that would make this much easier. – Andrea Jun 16 '11 at 15:49
  • While using the Twisted library may work, a whole library for one message seems a bit overkill. Perhaps you need to have CRON open a subprocess with your socket communication going on in a separate thread. That way you'll avoid the blocking issue. – chisaipete Jun 16 '11 at 20:37
  • @Andrea since I have similar question to the one posted. Is Twisted not designed for the Server Side? How to modify it to use on client side? – Hangon Sep 12 '17 at 13:44
  • @Hangon these are not inherently different scenarios, both are CLI Python – Andrea Sep 12 '17 at 15:49

3 Answers3

11

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..'''
Seanny123
  • 8,776
  • 13
  • 68
  • 124
Felipe Cruz
  • 940
  • 5
  • 14
3

I'd recommend eventlet and green threads for this.

Twisted is a good library but a little steep learning curve for such a simple use case.

Check out some examples here.

marr75
  • 5,666
  • 1
  • 27
  • 41
1

Try, before receiving, putting a timeout on the socket:

comSocket.settimeout(5.0)
try:
    rawData = comSocket.recv(512)
except socket.timeout:
    print "No response from server"
Russell Borogove
  • 18,516
  • 4
  • 43
  • 50