summaryrefslogtreecommitdiffstats
path: root/Lib/SocketServer.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/SocketServer.py')
-rw-r--r--Lib/SocketServer.py256
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())