| 1 | """Generic socket server classes.
|
|---|
| 2 |
|
|---|
| 3 | This module tries to capture the various aspects of defining a server:
|
|---|
| 4 |
|
|---|
| 5 | For socket-based servers:
|
|---|
| 6 |
|
|---|
| 7 | - address family:
|
|---|
| 8 | - AF_INET{,6}: IP (Internet Protocol) sockets (default)
|
|---|
| 9 | - AF_UNIX: Unix domain sockets
|
|---|
| 10 | - others, e.g. AF_DECNET are conceivable (see <socket.h>
|
|---|
| 11 | - socket type:
|
|---|
| 12 | - SOCK_STREAM (reliable stream, e.g. TCP)
|
|---|
| 13 | - SOCK_DGRAM (datagrams, e.g. UDP)
|
|---|
| 14 |
|
|---|
| 15 | For request-based servers (including socket-based):
|
|---|
| 16 |
|
|---|
| 17 | - client address verification before further looking at the request
|
|---|
| 18 | (This is actually a hook for any processing that needs to look
|
|---|
| 19 | at the request before anything else, e.g. logging)
|
|---|
| 20 | - how to handle multiple requests:
|
|---|
| 21 | - synchronous (one request is handled at a time)
|
|---|
| 22 | - forking (each request is handled by a new process)
|
|---|
| 23 | - threading (each request is handled by a new thread)
|
|---|
| 24 |
|
|---|
| 25 | The classes in this module favor the server type that is simplest to
|
|---|
| 26 | write: a synchronous TCP/IP server. This is bad class design, but
|
|---|
| 27 | save some typing. (There's also the issue that a deep class hierarchy
|
|---|
| 28 | slows down method lookups.)
|
|---|
| 29 |
|
|---|
| 30 | There are five classes in an inheritance diagram, four of which represent
|
|---|
| 31 | synchronous servers of four types:
|
|---|
| 32 |
|
|---|
| 33 | +------------+
|
|---|
| 34 | | BaseServer |
|
|---|
| 35 | +------------+
|
|---|
| 36 | |
|
|---|
| 37 | v
|
|---|
| 38 | +-----------+ +------------------+
|
|---|
| 39 | | TCPServer |------->| UnixStreamServer |
|
|---|
| 40 | +-----------+ +------------------+
|
|---|
| 41 | |
|
|---|
| 42 | v
|
|---|
| 43 | +-----------+ +--------------------+
|
|---|
| 44 | | UDPServer |------->| UnixDatagramServer |
|
|---|
| 45 | +-----------+ +--------------------+
|
|---|
| 46 |
|
|---|
| 47 | Note that UnixDatagramServer derives from UDPServer, not from
|
|---|
| 48 | UnixStreamServer -- the only difference between an IP and a Unix
|
|---|
| 49 | stream server is the address family, which is simply repeated in both
|
|---|
| 50 | unix server classes.
|
|---|
| 51 |
|
|---|
| 52 | Forking and threading versions of each type of server can be created
|
|---|
| 53 | using the ForkingMixIn and ThreadingMixIn mix-in classes. For
|
|---|
| 54 | instance, a threading UDP server class is created as follows:
|
|---|
| 55 |
|
|---|
| 56 | class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
|
|---|
| 57 |
|
|---|
| 58 | The Mix-in class must come first, since it overrides a method defined
|
|---|
| 59 | in UDPServer! Setting the various member variables also changes
|
|---|
| 60 | the behavior of the underlying server mechanism.
|
|---|
| 61 |
|
|---|
| 62 | To implement a service, you must derive a class from
|
|---|
| 63 | BaseRequestHandler and redefine its handle() method. You can then run
|
|---|
| 64 | various versions of the service by combining one of the server classes
|
|---|
| 65 | with your request handler class.
|
|---|
| 66 |
|
|---|
| 67 | The request handler class must be different for datagram or stream
|
|---|
| 68 | services. This can be hidden by using the request handler
|
|---|
| 69 | subclasses StreamRequestHandler or DatagramRequestHandler.
|
|---|
| 70 |
|
|---|
| 71 | Of course, you still have to use your head!
|
|---|
| 72 |
|
|---|
| 73 | For instance, it makes no sense to use a forking server if the service
|
|---|
| 74 | contains state in memory that can be modified by requests (since the
|
|---|
| 75 | modifications in the child process would never reach the initial state
|
|---|
| 76 | kept in the parent process and passed to each child). In this case,
|
|---|
| 77 | you can use a threading server, but you will probably have to use
|
|---|
| 78 | locks to avoid two requests that come in nearly simultaneous to apply
|
|---|
| 79 | conflicting changes to the server state.
|
|---|
| 80 |
|
|---|
| 81 | On the other hand, if you are building e.g. an HTTP server, where all
|
|---|
| 82 | data is stored externally (e.g. in the file system), a synchronous
|
|---|
| 83 | class will essentially render the service "deaf" while one request is
|
|---|
| 84 | being handled -- which may be for a very long time if a client is slow
|
|---|
| 85 | to reqd all the data it has requested. Here a threading or forking
|
|---|
| 86 | server is appropriate.
|
|---|
| 87 |
|
|---|
| 88 | In some cases, it may be appropriate to process part of a request
|
|---|
| 89 | synchronously, but to finish processing in a forked child depending on
|
|---|
| 90 | the request data. This can be implemented by using a synchronous
|
|---|
| 91 | server and doing an explicit fork in the request handler class
|
|---|
| 92 | handle() method.
|
|---|
| 93 |
|
|---|
| 94 | Another approach to handling multiple simultaneous requests in an
|
|---|
| 95 | environment that supports neither threads nor fork (or where these are
|
|---|
| 96 | too expensive or inappropriate for the service) is to maintain an
|
|---|
| 97 | explicit table of partially finished requests and to use select() to
|
|---|
| 98 | decide which request to work on next (or whether to handle a new
|
|---|
| 99 | incoming request). This is particularly important for stream services
|
|---|
| 100 | where each client can potentially be connected for a long time (if
|
|---|
| 101 | threads or subprocesses cannot be used).
|
|---|
| 102 |
|
|---|
| 103 | Future work:
|
|---|
| 104 | - Standard classes for Sun RPC (which uses either UDP or TCP)
|
|---|
| 105 | - Standard mix-in classes to implement various authentication
|
|---|
| 106 | and encryption schemes
|
|---|
| 107 | - Standard framework for select-based multiplexing
|
|---|
| 108 |
|
|---|
| 109 | XXX Open problems:
|
|---|
| 110 | - What to do with out-of-band data?
|
|---|
| 111 |
|
|---|
| 112 | BaseServer:
|
|---|
| 113 | - split generic "request" functionality out into BaseServer class.
|
|---|
| 114 | Copyright (C) 2000 Luke Kenneth Casson Leighton <[email protected]>
|
|---|
| 115 |
|
|---|
| 116 | example: read entries from a SQL database (requires overriding
|
|---|
| 117 | get_request() to return a table entry from the database).
|
|---|
| 118 | entry is processed by a RequestHandlerClass.
|
|---|
| 119 |
|
|---|
| 120 | """
|
|---|
| 121 |
|
|---|
| 122 | # Author of the BaseServer patch: Luke Kenneth Casson Leighton
|
|---|
| 123 |
|
|---|
| 124 | # XXX Warning!
|
|---|
| 125 | # There is a test suite for this module, but it cannot be run by the
|
|---|
| 126 | # standard regression test.
|
|---|
| 127 | # To run it manually, run Lib/test/test_socketserver.py.
|
|---|
| 128 |
|
|---|
| 129 | __version__ = "0.4"
|
|---|
| 130 |
|
|---|
| 131 |
|
|---|
| 132 | import socket
|
|---|
| 133 | import sys
|
|---|
| 134 | import os
|
|---|
| 135 |
|
|---|
| 136 | __all__ = ["TCPServer","UDPServer","ForkingUDPServer","ForkingTCPServer",
|
|---|
| 137 | "ThreadingUDPServer","ThreadingTCPServer","BaseRequestHandler",
|
|---|
| 138 | "StreamRequestHandler","DatagramRequestHandler",
|
|---|
| 139 | "ThreadingMixIn", "ForkingMixIn"]
|
|---|
| 140 | if hasattr(socket, "AF_UNIX"):
|
|---|
| 141 | __all__.extend(["UnixStreamServer","UnixDatagramServer",
|
|---|
| 142 | "ThreadingUnixStreamServer",
|
|---|
| 143 | "ThreadingUnixDatagramServer"])
|
|---|
| 144 |
|
|---|
| 145 | class BaseServer:
|
|---|
| 146 |
|
|---|
| 147 | """Base class for server classes.
|
|---|
| 148 |
|
|---|
| 149 | Methods for the caller:
|
|---|
| 150 |
|
|---|
| 151 | - __init__(server_address, RequestHandlerClass)
|
|---|
| 152 | - serve_forever()
|
|---|
| 153 | - handle_request() # if you do not use serve_forever()
|
|---|
| 154 | - fileno() -> int # for select()
|
|---|
| 155 |
|
|---|
| 156 | Methods that may be overridden:
|
|---|
| 157 |
|
|---|
| 158 | - server_bind()
|
|---|
| 159 | - server_activate()
|
|---|
| 160 | - get_request() -> request, client_address
|
|---|
| 161 | - verify_request(request, client_address)
|
|---|
| 162 | - server_close()
|
|---|
| 163 | - process_request(request, client_address)
|
|---|
| 164 | - close_request(request)
|
|---|
| 165 | - handle_error()
|
|---|
| 166 |
|
|---|
| 167 | Methods for derived classes:
|
|---|
| 168 |
|
|---|
| 169 | - finish_request(request, client_address)
|
|---|
| 170 |
|
|---|
| 171 | Class variables that may be overridden by derived classes or
|
|---|
| 172 | instances:
|
|---|
| 173 |
|
|---|
| 174 | - address_family
|
|---|
| 175 | - socket_type
|
|---|
| 176 | - allow_reuse_address
|
|---|
| 177 |
|
|---|
| 178 | Instance variables:
|
|---|
| 179 |
|
|---|
| 180 | - RequestHandlerClass
|
|---|
| 181 | - socket
|
|---|
| 182 |
|
|---|
| 183 | """
|
|---|
| 184 |
|
|---|
| 185 | def __init__(self, server_address, RequestHandlerClass):
|
|---|
| 186 | """Constructor. May be extended, do not override."""
|
|---|
| 187 | self.server_address = server_address
|
|---|
| 188 | self.RequestHandlerClass = RequestHandlerClass
|
|---|
| 189 |
|
|---|
| 190 | def server_activate(self):
|
|---|
| 191 | """Called by constructor to activate the server.
|
|---|
| 192 |
|
|---|
| 193 | May be overridden.
|
|---|
| 194 |
|
|---|
| 195 | """
|
|---|
| 196 | pass
|
|---|
| 197 |
|
|---|
| 198 | def serve_forever(self):
|
|---|
| 199 | """Handle one request at a time until doomsday."""
|
|---|
| 200 | while 1:
|
|---|
| 201 | self.handle_request()
|
|---|
| 202 |
|
|---|
| 203 | # The distinction between handling, getting, processing and
|
|---|
| 204 | # finishing a request is fairly arbitrary. Remember:
|
|---|
| 205 | #
|
|---|
| 206 | # - handle_request() is the top-level call. It calls
|
|---|
| 207 | # get_request(), verify_request() and process_request()
|
|---|
| 208 | # - get_request() is different for stream or datagram sockets
|
|---|
| 209 | # - process_request() is the place that may fork a new process
|
|---|
| 210 | # or create a new thread to finish the request
|
|---|
| 211 | # - finish_request() instantiates the request handler class;
|
|---|
| 212 | # this constructor will handle the request all by itself
|
|---|
| 213 |
|
|---|
| 214 | def handle_request(self):
|
|---|
| 215 | """Handle one request, possibly blocking."""
|
|---|
| 216 | try:
|
|---|
| 217 | request, client_address = self.get_request()
|
|---|
| 218 | except socket.error:
|
|---|
| 219 | return
|
|---|
| 220 | if self.verify_request(request, client_address):
|
|---|
| 221 | try:
|
|---|
| 222 | self.process_request(request, client_address)
|
|---|
| 223 | except:
|
|---|
| 224 | self.handle_error(request, client_address)
|
|---|
| 225 | self.close_request(request)
|
|---|
| 226 |
|
|---|
|
|---|