Python Sockets Select is hanging - Doing other tasks while waiting for socket data?
<p>I am rather a noob here, but trying to setup a script where I can poll a socket, and when no socket data has been sent, a loop continues to run and do other things. I have been playing with several examples I found using select(), but no matter how I organize the code, it seems to stop on or near the server.recv() line and wait for a response. I want to skip out of this if no data has been sent by a client, or if no client connection exists.</p>

<p>Note that this application does not require the server script to send any reply data, if it makes any difference.</p>

<p>The actual application is to run a loop and animate some LEDs (which needs root access to the I/O on a Raspberry Pi). I am going to send this script data from another separate script via sockets that will pass in control parameters for the animations. This way the external script does not require root access.</p>

<p>So far the sending and receiving of data works great, I just can't get loop to keep spinning in the absence of incoming data. It is my understanding that this is what select() was intended to allow, but the examples I've found don't seem to be working that way.</p>

<p>I have attempted adding server.setblocking(0) a few different places to no avail. (If I understand correctly a non-blocking instance should allow the code to skip over the recv() if no data has been sent, but I may be off on this).</p>

<p>I have based my code on an example here:
<a href="http://ilab.cs.byu.edu/python/select/echoserver.html" rel="nofollow">http://ilab.cs.byu.edu/python/select/echoserver.html</a></p>

<p>Here is the server side script followed by the client side script.</p>

<p><strong>Server Code:  sockselectserver.py</strong></p>

<pre><code>#!/usr/bin/env python

import select
import socket
import sys

server = socket.socket()
host = socket.gethostname()
port = 20568
size = 1024
server.bind((host,port))
server.listen(5)
input = [server,sys.stdin]
running = 1
while running:
    inputready,outputready,exceptready = select.select(input,[],[])

    for s in inputready:

        if s == server:
            # handle the server socket
            client, address = server.accept()
            input.append(client)

        elif s == sys.stdin:
            # handle standard input
            junk = sys.stdin.readline()
            running = 0

        else:
            # handle all other sockets
            data = s.recv(size)
            if data:
                s.send(data)
            else:
                s.close()
                input.remove(s)
    print "looping"
server.close()
</code></pre>

<p><strong>Client Code: skclient.py</strong></p>

<pre><code>#!/usr/bin/python           # This is client.py file

import socket               # Import socket module

s = socket.socket()         # Create a socket object
host = socket.gethostname() # Get local machine name
port = 20568                # Reserve a port for your service.

s.connect((host, port))

data = "123:120:230:51:210:120:55:12:35:24"
s.send(data)
print s.recv(1024)
s.close                     # Close the socket when done
</code></pre>

<p>What I would like to achieve by this example is to see "looping" repeated forever, then when the client script sends data, see that data print, then see the "looping" resume printing over and over. That would tell me it's doing what is intended I can take it from there.</p>

<p>Interesting enough, when I test this as is, whenever I run the client, I see "looping" printed 3 times on the screen, then no more. I don't fully understand what is happening inside the select, but I'd assume it would only print 1 time.</p>

<p>I tried moving the inputready.. select.select() around to different places but found it appears to need to be called each time, otherwise the server stops responding (for example if it is called once prior to the endless while: loop).</p>

<p>I'm hoping this can be made simple enough that it can be taught to other hacker types in a maker class, so I'm hopeful I don't need to get too crazy with multi-threading and more elaborate solutions. As a last resort I'm considering logging all my parameters to mySQL from the external script then using this script to query them back out of tables. I've got experience there and would probably work, but it seems this socket angle would be a more direct solution.</p>

<p>Any help very much appreciated.</p>

<p>Great news. This was an easy fix, wanted to post in case anyone else needed it. The suggestion from acw1668 above got me going.</p>

<p>Simply added a timeout of "0" to the select.select() like this:</p>

<pre><code>inputready,outputready,exceptready = select.select(input,[],[],0)
</code></pre>

<p>This is in the python docs but somehow I missed it. Link here: <a href="https://docs.python.org/2/library/select.html" rel="nofollow">https://docs.python.org/2/library/select.html</a></p>

<p>Per the docs:
"The optional timeout argument specifies a time-out as a floating point number in seconds. When the timeout argument is omitted the function blocks until at least one file descriptor is ready. A time-out value of zero specifies a poll and never blocks."</p>

<p>I tested the same code as above, adding a delay of 5 seconds using time.sleep(5) right after the print "looping" line. With the delay, if no data or client is present the code just loops every 5 seconds and prints "looping" to the screen. If I kick off the client script during the 5 second delay, it pauses and the message is processed the next time the 5 second delay ends. Occasionally it doesn't respond the very next loop, but rather the loop following. I assume this is because the first time through the server.accept is running and the next time through the s.recv() is running which actually exchanges the data.</p>

python multithreading sockets select