BYUBRIGHAM YOUNG UNIVERSITY
Computer Science
Python Network Programming

The Select Module

Echo Server with Select

Here is modified echo server that uses select (echoserver-select.py):

#!/usr/bin/env python

"""
An echo server that uses select to handle multiple clients at a time.
Entering any line of input at the terminal will exit the server.
"""

import select
import socket
import sys

host = ''
port = 50000
backlog = 5
size = 1024
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host,port))
server.listen(backlog)
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)
server.close()

Let's go through the code again:

import select
import socket
import sys

host = ''
port = 50000
backlog = 5
size = 1024
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host,port))
server.listen(backlog)

All of this is about the same as before -- the server has just two more import statements for both the select and sys modules. The sys module provides access to standard input.

input = [server,sys.stdin]

This line creates a list of input objects that is initialized to contain the server socket and standard input. The server will use this for the select() method so that it can wait for both new clients and anything typed at the keyboard.

running = 1
while running:
    inputready,outputready,exceptready = select.select(input,[],[])

This starts a while loop; inside the loop the server calls select() to see if any of the input sockets (or files) are ready. Note that the server passes two additional empty lists to select, one for the output sockets and one for the exception sockets. In this example the server doesn't have any sockets of these types.

Note that the server uses three new lists to capture the return value of the select() call. The server needs to be careful not to overwrite its list of all sockets with the list of sockets ready for input.

    for s in inputready:

The server now starts a for loop in which it will handle any sockets that are ready. Since the server did not specify a timeout for select, this list should have at least one element in it. Even if it is empty, the server will just loop back to select.

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

Both the server socket and standard input are special cases. For the server socket an input event means a new client is trying to contact the server. The server calls accept() to get the new client and then appends the client to its list of input sockets. This means that next time it calls select() it can handle any input the client has sent on this new socket.

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

Our next special case is input at the keyboard. If this case occurs the server reads one line from standard input and then sets the running variable to zero. This causes the while loop to terminate after it has handled any pending client requests.

        else:
            # handle all other sockets
            data = s.recv(size)
            if data:
                s.send(data)
            else:
                s.close()
                input.remove(s)

Finally, the server handles any client requests. It reads data from the socket and if this call succeeds it echoes the data back to the client. If it is unable to read any data, this means the client has closed the connection, so it closes its end of the socket and removes the client from the input list.