[code.view]

[top] / python / PyMOTW / select / select_poll_echo_server.py

     #!/usr/bin/env python
     # encoding: utf-8
     #
     # Copyright (c) 2010 Doug Hellmann.  All rights reserved.
     #
     """Server half of echo example.
     """
     #end_pymotw_header
     
     import select
     import socket
     import sys
     import Queue
     
     # Create a TCP/IP socket
     server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     server.setblocking(0)
     
     # Bind the socket to the port
     server_address = ('localhost', 10000)
     print >>sys.stderr, 'starting up on %s port %s' % server_address
     server.bind(server_address)
     
     # Listen for incoming connections
     server.listen(5)
     
     # Keep up with the queues of outgoing messages
     message_queues = {}
     
     # Do not block forever (milliseconds)
     TIMEOUT = 1000
     
     # Commonly used flag setes
     READ_ONLY = select.POLLIN | select.POLLPRI | select.POLLHUP | select.POLLERR
     READ_WRITE = READ_ONLY | select.POLLOUT
     
     # Set up the poller
     poller = select.poll()
     poller.register(server, READ_ONLY)
     
     # Map file descriptors to socket objects
     fd_to_socket = { server.fileno(): server,
                    }
     
     while True:
     
         # Wait for at least one of the sockets to be ready for processing
         print >>sys.stderr, '\nwaiting for the next event'
         events = poller.poll(TIMEOUT)
     
         for fd, flag in events:
     
             # Retrieve the actual socket from its file descriptor
             s = fd_to_socket[fd]
     
             # Handle inputs
             if flag & (select.POLLIN | select.POLLPRI):
     
                 if s is server:
                     # A "readable" server socket is ready to accept a connection
                     connection, client_address = s.accept()
                     print >>sys.stderr, 'new connection from', client_address
                     connection.setblocking(0)
                     fd_to_socket[ connection.fileno() ] = connection
                     poller.register(connection, READ_ONLY)
     
                     # Give the connection a queue for data we want to send
                     message_queues[connection] = Queue.Queue()
     
                 else:
                     data = s.recv(1024)
                     if data:
                         # A readable client socket has data
                         print >>sys.stderr, 'received "%s" from %s' % (data, s.getpeername())
                         message_queues[s].put(data)
                         # Add output channel for response
                         poller.modify(s, READ_WRITE)
     
                     else:
                         # Interpret empty result as closed connection
                         print >>sys.stderr, 'closing', client_address, 'after reading no data'
                         # Stop listening for input on the connection
                         poller.unregister(s)
                         s.close()
     
             elif flag & select.POLLHUP:
                 # Client hung up
                 print >>sys.stderr, 'closing', client_address, 'after receiving HUP'
                 # Stop listening for input on the connection
                 poller.unregister(s)
                 s.close()
     
             elif flag & select.POLLOUT:
                 # Socket is ready to send data, if there is any to send.
                 try:
                     next_msg = message_queues[s].get_nowait()
                 except Queue.Empty:
                     # No messages waiting so stop checking for writability.
                     print >>sys.stderr, 'output queue for', s.getpeername(), 'is empty'
                     poller.modify(s, READ_ONLY)
                 else:
                     print >>sys.stderr, 'sending "%s" to %s' % (next_msg, s.getpeername())
                     s.send(next_msg)
     
             elif flag & select.POLLERR:
                 print >>sys.stderr, 'handling exceptional condition for', s.getpeername()
                 # Stop listening for input on the connection
                 poller.unregister(s)
                 s.close()
     

[top] / python / PyMOTW / select / select_poll_echo_server.py

contact | logmethods.com