portsock.bind((myHost, myPort)) # bind it to server port number
portsock.listen(5) # listen, allow 5 pending connects
mainsocks.append(portsock) # add to main list to identify
readsocks.append(portsock) # add to select inputs list
myPort += 1 # bind on consecutive ports
event loop: listen and multiplex until server process killed
print('select-server loop starting')
while True:
#print(readsocks)
readables, writeables, exceptions = select(readsocks, writesocks, [])
for sockobj in readables:
if sockobj in mainsocks: # for ready input sockets
port socket: accept new client
newsock, address = sockobj.accept() # accept should not block
print('Connect:', address, id(newsock)) # newsock is a new socket
readsocks.append(newsock) # add to select list, wait
else:
client socket: read next line
data = sockobj.recv(1024) # recv should not block
print('\tgot', data, 'on', id(sockobj))
if not data: # if closed by the clients
sockobj.close() # close here and remv from
readsocks.remove(sockobj) # del list else reselected
else:
this may block: should really select for writes too
reply = 'Echo=>%s at %s' % (data, now())
sockobj.send(reply.encode())
The bulk of this script is its while event loop at the end that calls select to find out
which sockets are ready for processing; these include both main port sockets on which
clients can connect and open client connections. It then loops over all such ready sock-
ets, accepting connections on main port sockets and reading and echoing input on any
client sockets ready for input. Both the accept and recv calls in this code are guaranteed
to not block the server process after select returns; as a result, this server can quickly
get back to the top of the loop to process newly arrived client requests and already
connected clients’ inputs. The net effect is that all new requests and clients are serviced
in pseudoparallel fashion.
To make this process work, the server appends the connected socket for each client to
the readables list passed to select, and simply waits for the socket to show up in the
selected inputs list. For illustration purposes, this server also listens for new clients on
more than one port—on ports 50007 and 50008, in our examples. Because these main
port sockets are also interrogated with select, connection requests on either port can
be accepted without blocking either already connected clients or new connection re-
quests appearing on the other port. The select call returns whatever sockets in
readables are ready for processing—both main port sockets and sockets connected to
clients currently being processed.
822 | Chapter 12: Network Scripting