--- SocketServer.py.cvs Wed May 21 15:28:39 2003 +++ SocketServer.py Fri May 23 15:38:48 2003 @@ -128,7 +128,6 @@ __version__ = "0.4" - import socket import sys import os @@ -158,6 +157,7 @@ - server_bind() - server_activate() - get_request() -> request, client_address + - handle_timeout() - verify_request(request, client_address) - server_close() - process_request(request, client_address) @@ -171,9 +171,10 @@ Class variables that may be overridden by derived classes or instances: + - timeout - address_family - socket_type - - reuse_address + - allow_reuse_address Instance variables: @@ -182,6 +183,8 @@ """ + timeout = None + def __init__(self, server_address, RequestHandlerClass): """Constructor. May be extended, do not override.""" self.server_address = server_address @@ -204,8 +207,9 @@ # finishing a request is fairly arbitrary. Remember: # # - handle_request() is the top-level call. It calls - # get_request(), verify_request() and process_request() - # - get_request() is different for stream or datagram sockets + # await_request(), verify_request() and process_request() + # - get_request(), called by await_request() is different for + # stream or datagram sockets # - process_request() is the place that may fork a new process # or create a new thread to finish the request # - finish_request() instantiates the request handler class; @@ -214,7 +218,7 @@ def handle_request(self): """Handle one request, possibly blocking.""" try: - request, client_address = self.get_request() + request, client_address = self.await_request() except socket.error: return if self.verify_request(request, client_address): @@ -224,6 +228,28 @@ self.handle_error(request, client_address) self.close_request(request) + def await_request(self): + """Call get_request or handle_timeout, observing self.timeout. + + Returns as get_request or raises socket.error exception if + timeout was exceeded. + """ + if self.timeout is not None: + # If timeout == 0, you're responsible for your own fd magic! + import select + fd_sets = select.select([self,], [], [], self.timeout) + if not len(fd_sets[0]): + self.handle_timeout() + raise socket.error("eimpatient") + return self.get_request() + + def handle_timeout(self): + """Called if no new request arrives within self.timeout. + + Overridden by ForkingMixIn. + """ + pass + def verify_request(self, request, client_address): """Verify the request. May be overridden. @@ -289,6 +315,7 @@ - server_bind() - server_activate() - get_request() -> request, client_address + - handle_timeout() - verify_request(request, client_address) - process_request(request, client_address) - close_request(request) @@ -301,10 +328,11 @@ Class variables that may be overridden by derived classes or instances: + - timeout - address_family - socket_type - request_queue_size (only for stream sockets) - - reuse_address + - allow_reuse_address Instance variables: @@ -403,6 +431,7 @@ """Mix-in class to handle each request in a new process.""" + timeout = 300 active_children = None max_children = 40 @@ -422,6 +451,13 @@ if not pid: break self.active_children.remove(pid) + def handle_timeout(self): + """Wait for zombies after self.timeout seconds of inactivity. + + May be extended, do not override. + """ + self.collect_children() + def process_request(self, request, client_address): """Fork a new subprocess to process the request.""" self.collect_children()