Harvey
Harvey

Reputation: 1418

Python TCP Sockets: How to know if a specific connection has sent information

I have a multi-threaded Python 3 application that on thread #1 accepts TCP socket communications. Thread #2 will check all current connections if they have anything to receive, then act accordingly.

So, currently I have a list called all_connections which is a list of accepted socket connection objects.

Using for connection in all_connections: I can loop through all the connection objects. I know I use conn.recv(256) to check if there is anything ready to recive on this socket. Will this block the loop though untill there is something to receive? I have set conn.setblocking(1) beforehand although Im unsure if this is the best way to get around it:

Here is some example code:

Thread 1

self.all_connections = [] # init a list to hold connection objs
while 1:
    try:
        conn, address = self.socket.accept()
        conn.setblocking(1) # non blocking
    except Exception as e:
        continue
    self.all_connections.append(conn) # Save the connection object

Thread 2

while True:
    for connection in self.all_connections:
        received = connection.recv(256)
return

So, I'm only interested in connections that have actually sent something, as I will be sending them something back most likely.

I know I can use select.select in order to check if there is anything to receive on the socket, but that wouldn't help me reference the specific connection.

Upvotes: 1

Views: 667

Answers (1)

mhawke
mhawke

Reputation: 87134

Yes, read() will block; this is the default behaviour. Calling socket.setblocking(1) actually enables blocking, which is opposite of what you wanted. setblocking(False) will set non-blocking mode. I/O on non-blocking sockets requires that you use exception handling.

A better way, and you are already headed in the right direction, is to use select(). You do in fact know which socket sent data because select() returns a list of sockets that are available for reading, writing, or that have an error status. You pass to select() a list of the sockets that you are interested in and it returns those that are available for I/O. Here is the function signature:

select(...)
    select(rlist, wlist, xlist[, timeout]) -> (rlist, wlist, xlist)

So the code in thread 2 would look something like this:

from select import select

while True:
      rlist, wlist, xlist = select(self.all_connections, [], [])
      for connection in rlist:
          received = connection.recv(256)

The above code only checks for readable sockets in the list of all connections and reads data from those that are ready. The read will not block.

Upvotes: 2

Related Questions