diff options
Diffstat (limited to 'Lib/SocketServer.py')
-rw-r--r-- | Lib/SocketServer.py | 256 |
1 files changed, 128 insertions, 128 deletions
diff --git a/Lib/SocketServer.py b/Lib/SocketServer.py index 049a4b6..64a86d1 100644 --- a/Lib/SocketServer.py +++ b/Lib/SocketServer.py @@ -3,19 +3,19 @@ This module tries to capture the various aspects of defining a server: - address family: - - AF_INET: IP (Internet Protocol) sockets (default) - - AF_UNIX: Unix domain sockets - - others, e.g. AF_DECNET are conceivable (see <socket.h> + - AF_INET: IP (Internet Protocol) sockets (default) + - AF_UNIX: Unix domain sockets + - others, e.g. AF_DECNET are conceivable (see <socket.h> - socket type: - - SOCK_STREAM (reliable stream, e.g. TCP) - - SOCK_DGRAM (datagrams, e.g. UDP) + - SOCK_STREAM (reliable stream, e.g. TCP) + - SOCK_DGRAM (datagrams, e.g. UDP) - client address verification before further looking at the request - (This is actually a hook for any processing that needs to look - at the request before anything else, e.g. logging) + (This is actually a hook for any processing that needs to look + at the request before anything else, e.g. logging) - how to handle multiple requests: - - synchronous (one request is handled at a time) - - forking (each request is handled by a new process) - - threading (each request is handled by a new thread) + - synchronous (one request is handled at a time) + - forking (each request is handled by a new process) + - threading (each request is handled by a new thread) The classes in this module favor the server type that is simplest to write: a synchronous TCP/IP server. This is bad class design, but @@ -25,14 +25,14 @@ slows down method lookups.) There are four classes in an inheritance diagram that represent synchronous servers of four types: - +-----------+ +------------------+ - | TCPServer |------->| UnixStreamServer | - +-----------+ +------------------+ - | - v - +-----------+ +--------------------+ - | UDPServer |------->| UnixDatagramServer | - +-----------+ +--------------------+ + +-----------+ +------------------+ + | TCPServer |------->| UnixStreamServer | + +-----------+ +------------------+ + | + v + +-----------+ +--------------------+ + | UDPServer |------->| UnixDatagramServer | + +-----------+ +--------------------+ Note that UnixDatagramServer derives from UDPServer, not from UnixStreamServer -- the only difference between an IP and a Unix @@ -43,7 +43,7 @@ Forking and threading versions of each type of server can be created using the ForkingServer and ThreadingServer mix-in classes. For instance, a threading UDP server class is created as follows: - class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass + class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass The Mix-in class must come first, since it overrides a method defined in UDPServer! @@ -119,8 +119,8 @@ class TCPServer: - __init__(server_address, RequestHandlerClass) - serve_forever() - - handle_request() # if you don't use serve_forever() - - fileno() -> int # for select() + - handle_request() # if you don't use serve_forever() + - fileno() -> int # for select() Methods that may be overridden: @@ -157,42 +157,42 @@ class TCPServer: request_queue_size = 5 def __init__(self, server_address, RequestHandlerClass): - """Constructor. May be extended, do not override.""" - self.server_address = server_address - self.RequestHandlerClass = RequestHandlerClass - self.socket = socket.socket(self.address_family, - self.socket_type) - self.server_bind() - self.server_activate() + """Constructor. May be extended, do not override.""" + self.server_address = server_address + self.RequestHandlerClass = RequestHandlerClass + self.socket = socket.socket(self.address_family, + self.socket_type) + self.server_bind() + self.server_activate() def server_bind(self): - """Called by constructor to bind the socket. + """Called by constructor to bind the socket. - May be overridden. + May be overridden. - """ - self.socket.bind(self.server_address) + """ + self.socket.bind(self.server_address) def server_activate(self): - """Called by constructor to activate the server. + """Called by constructor to activate the server. - May be overridden. + May be overridden. - """ - self.socket.listen(self.request_queue_size) + """ + self.socket.listen(self.request_queue_size) def fileno(self): - """Return socket file number. + """Return socket file number. - Interface required by select(). + Interface required by select(). - """ - return self.socket.fileno() + """ + return self.socket.fileno() def serve_forever(self): - """Handle one request at a time until doomsday.""" - while 1: - self.handle_request() + """Handle one request at a time until doomsday.""" + while 1: + self.handle_request() # The distinction between handling, getting, processing and # finishing a request is fairly arbitrary. Remember: @@ -206,54 +206,54 @@ class TCPServer: # this constructor will handle the request all by itself def handle_request(self): - """Handle one request, possibly blocking.""" - request, client_address = self.get_request() - if self.verify_request(request, client_address): - try: - self.process_request(request, client_address) - except: - self.handle_error(request, client_address) + """Handle one request, possibly blocking.""" + request, client_address = self.get_request() + if self.verify_request(request, client_address): + try: + self.process_request(request, client_address) + except: + self.handle_error(request, client_address) def get_request(self): - """Get the request and client address from the socket. + """Get the request and client address from the socket. - May be overridden. + May be overridden. - """ - return self.socket.accept() + """ + return self.socket.accept() def verify_request(self, request, client_address): - """Verify the request. May be overridden. + """Verify the request. May be overridden. - Return true if we should proceed with this request. + Return true if we should proceed with this request. - """ - return 1 + """ + return 1 def process_request(self, request, client_address): - """Call finish_request. + """Call finish_request. - Overridden by ForkingMixIn and ThreadingMixIn. + Overridden by ForkingMixIn and ThreadingMixIn. - """ - self.finish_request(request, client_address) + """ + self.finish_request(request, client_address) def finish_request(self, request, client_address): - """Finish one request by instantiating RequestHandlerClass.""" - self.RequestHandlerClass(request, client_address, self) + """Finish one request by instantiating RequestHandlerClass.""" + self.RequestHandlerClass(request, client_address, self) def handle_error(self, request, client_address): - """Handle an error gracefully. May be overridden. + """Handle an error gracefully. May be overridden. - The default is to print a traceback and continue. + The default is to print a traceback and continue. - """ - print '-'*40 - print 'Exception happened during processing of request from', - print client_address - import traceback - traceback.print_exc() - print '-'*40 + """ + print '-'*40 + print 'Exception happened during processing of request from', + print client_address + import traceback + traceback.print_exc() + print '-'*40 class UDPServer(TCPServer): @@ -265,19 +265,19 @@ class UDPServer(TCPServer): max_packet_size = 8192 def get_request(self): - return self.socket.recvfrom(self.max_packet_size) + return self.socket.recvfrom(self.max_packet_size) if hasattr(socket, 'AF_UNIX'): class UnixStreamServer(TCPServer): - address_family = socket.AF_UNIX + address_family = socket.AF_UNIX class UnixDatagramServer(UDPServer): - address_family = socket.AF_UNIX + address_family = socket.AF_UNIX class ForkingMixIn: @@ -287,34 +287,34 @@ class ForkingMixIn: active_children = None def collect_children(self): - """Internal routine to wait for died children.""" - while self.active_children: - pid, status = os.waitpid(0, os.WNOHANG) - if not pid: break - self.active_children.remove(pid) + """Internal routine to wait for died children.""" + while self.active_children: + pid, status = os.waitpid(0, os.WNOHANG) + if not pid: break + self.active_children.remove(pid) def process_request(self, request, client_address): - """Fork a new subprocess to process the request.""" - self.collect_children() - pid = os.fork() - if pid: - # Parent process - if self.active_children is None: - self.active_children = [] - self.active_children.append(pid) - return - else: - # Child process. - # This must never return, hence os._exit()! - try: - self.finish_request(request, client_address) - os._exit(0) - except: - try: - self.handle_error(request, - client_address) - finally: - os._exit(1) + """Fork a new subprocess to process the request.""" + self.collect_children() + pid = os.fork() + if pid: + # Parent process + if self.active_children is None: + self.active_children = [] + self.active_children.append(pid) + return + else: + # Child process. + # This must never return, hence os._exit()! + try: + self.finish_request(request, client_address) + os._exit(0) + except: + try: + self.handle_error(request, + client_address) + finally: + os._exit(1) class ThreadingMixIn: @@ -322,10 +322,10 @@ class ThreadingMixIn: """Mix-in class to handle each request in a new thread.""" def process_request(self, request, client_address): - """Start a new thread to process the request.""" - import thread - thread.start_new_thread(self.finish_request, - (request, client_address)) + """Start a new thread to process the request.""" + import thread + thread.start_new_thread(self.finish_request, + (request, client_address)) class ForkingUDPServer(ForkingMixIn, UDPServer): pass @@ -354,27 +354,27 @@ class BaseRequestHandler: """ def __init__(self, request, client_address, server): - self.request = request - self.client_address = client_address - self.server = server - try: - self.setup() - self.handle() - self.finish() - finally: - sys.exc_traceback = None # Help garbage collection + self.request = request + self.client_address = client_address + self.server = server + try: + self.setup() + self.handle() + self.finish() + finally: + sys.exc_traceback = None # Help garbage collection def setup(self): - pass + pass def __del__(self): - pass + pass def handle(self): - pass + pass def finish(self): - pass + pass # The following two classes make it possible to use the same service @@ -390,12 +390,12 @@ class StreamRequestHandler(BaseRequestHandler): """Define self.rfile and self.wfile for stream sockets.""" def setup(self): - self.connection = self.request - self.rfile = self.connection.makefile('rb', 0) - self.wfile = self.connection.makefile('wb', 0) + self.connection = self.request + self.rfile = self.connection.makefile('rb', 0) + self.wfile = self.connection.makefile('wb', 0) def finish(self): - self.wfile.flush() + self.wfile.flush() class DatagramRequestHandler(BaseRequestHandler): @@ -403,10 +403,10 @@ class DatagramRequestHandler(BaseRequestHandler): """Define self.rfile and self.wfile for datagram sockets.""" def setup(self): - import StringIO - self.packet, self.socket = self.request - self.rfile = StringIO.StringIO(self.packet) - self.wfile = StringIO.StringIO(self.packet) + import StringIO + self.packet, self.socket = self.request + self.rfile = StringIO.StringIO(self.packet) + self.wfile = StringIO.StringIO(self.packet) def finish(self): - self.socket.send(self.wfile.getvalue()) + self.socket.send(self.wfile.getvalue()) |