Sockets/select: how to deal with multiple connections in threads?

Irmen de Jong irmen at USENET_NOSPAM_REMOVETHISxs4all.nl
Sun May 26 07:29:34 EDT 2002


Hi,
I have something that works for now, but I'd like your advice & ideas.

I have a socket server that has to deal with multiple concurrent connections.
(FYI, the SocketServer module is not appropriate).
What I'm currently doing is the following:

main loop uses select() on the current connection list.
if a new connection arrives, add this new socket to the connection list.
if data is available on a socket, spawn a new thread to read the data.

There are some subtleties:
If I don't remove the socket from the connection list while the thread
is reading the data, the select() in the main loop keeps on returing
with that socket (probably to be expected, because the thread hasn't
read all data yet, so the socket is still ready for reading).
So what I do, just before spawning the thread, I remove the socket
from the connection list. The thread adds it back to the list when
it has read all data. Next time around, the select() in the main loop
will also wait on that socket again.

Problems arise, because even though the thread has added the socket
back to the connection list, the select() in the main loop is still
waiting on the *old* list, that hasn't got the socket! My app blocks!
Adding a timeout to the select fixes things, but introduces an
unwanted delay between socket activity (only after ~delay/2 the
select() times out and reenters the loop with the new connection list).

My solution is currently to have *another* server socket, and a
loopback socket to that socket. The select() will wait on this 'signal'
server socket too. The thread will write a character to the loopback
socket, and so the select() in the main loop breaks and my cycle continues.

I'm not too happy with this solution. Who has a better idea?
What is usually done to abort a select()?  (has to work on Windows too)

Thanks!!!
Irmen de Jong

PS example code below:

#! /usr/bin/env python

import sys
from socket import *
import select
from threading import Thread
import signal


def read(c,conns,s):
        print 'READING FROM',c.getpeername()
        m=''
        while len(m)<10:
                d=c.recv(10)
                if not d:
                        print 'connection lost'
                        return
                else:
                        m+=d
        print ' GOT :',m
        conns.append(c)
        s.send("!") # signal to break select()


def main():
        port = int(eval(sys.argv[1]))
        # create server socket 's'
        s = socket(AF_INET, SOCK_STREAM)
        s.bind(('', port))
        s.listen(1)
        # create signal socket to break select()
        ssock=socket(AF_INET,SOCK_STREAM)
        ssock.bind(('',port+1))
        ssock.listen(1)
        sigsock=socket(AF_INET,SOCK_STREAM)
        sigsock.connect(ssock.getsockname())
        sigssock,foo = ssock.accept()

        conns=[s,sigssock]

        while 1:
                ins,outs,exs=select.select(conns,[],[])
                if ins:
                        print 'GOT INS',ins
                        if sigssock in ins:
                                print 'SIGNAL!'
                                ins.remove(sigssock)
                                sigssock.recv(10) # ignore any data
                        if s in ins:
                                conn, addr = s.accept()
                                print 'connected by', addr
                                conns.append(conn)
                                ins.remove(s)
                        for c in ins:
                                conns.remove(c)
                                Thread(target=read,
                                  args=(c,conns,sigsock)).start()

if __name__=='__main__':
        main()




More information about the Python-list mailing list