SocketServer.py 18.1 KB
Newer Older
Guido van Rossum's avatar
Guido van Rossum committed
1 2 3 4
"""Generic socket server classes.

This module tries to capture the various aspects of defining a server:

5 6
For socket-based servers:

Guido van Rossum's avatar
Guido van Rossum committed
7
- address family:
8
        - AF_INET{,6}: IP (Internet Protocol) sockets (default)
9 10
        - AF_UNIX: Unix domain sockets
        - others, e.g. AF_DECNET are conceivable (see <socket.h>
Guido van Rossum's avatar
Guido van Rossum committed
11
- socket type:
12 13
        - SOCK_STREAM (reliable stream, e.g. TCP)
        - SOCK_DGRAM (datagrams, e.g. UDP)
14 15 16

For request-based servers (including socket-based):

Guido van Rossum's avatar
Guido van Rossum committed
17
- client address verification before further looking at the request
18 19
        (This is actually a hook for any processing that needs to look
         at the request before anything else, e.g. logging)
Guido van Rossum's avatar
Guido van Rossum committed
20
- how to handle multiple requests:
21 22 23
        - 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)
Guido van Rossum's avatar
Guido van Rossum committed
24 25 26 27 28 29

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
save some typing.  (There's also the issue that a deep class hierarchy
slows down method lookups.)

30
There are five classes in an inheritance diagram, four of which represent
Guido van Rossum's avatar
Guido van Rossum committed
31 32
synchronous servers of four types:

33 34 35 36 37
        +------------+
        | BaseServer |
        +------------+
              |
              v
38 39 40 41 42 43 44 45
        +-----------+        +------------------+
        | TCPServer |------->| UnixStreamServer |
        +-----------+        +------------------+
              |
              v
        +-----------+        +--------------------+
        | UDPServer |------->| UnixDatagramServer |
        +-----------+        +--------------------+
Guido van Rossum's avatar
Guido van Rossum committed
46

47
Note that UnixDatagramServer derives from UDPServer, not from
Guido van Rossum's avatar
Guido van Rossum committed
48 49
UnixStreamServer -- the only difference between an IP and a Unix
stream server is the address family, which is simply repeated in both
50
unix server classes.
Guido van Rossum's avatar
Guido van Rossum committed
51 52

Forking and threading versions of each type of server can be created
53
using the ForkingMixIn and ThreadingMixIn mix-in classes.  For
Guido van Rossum's avatar
Guido van Rossum committed
54 55
instance, a threading UDP server class is created as follows:

56
        class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
Guido van Rossum's avatar
Guido van Rossum committed
57

58
The Mix-in class must come first, since it overrides a method defined
59 60
in UDPServer! Setting the various member variables also changes
the behavior of the underlying server mechanism.
Guido van Rossum's avatar
Guido van Rossum committed
61 62 63 64 65 66 67

To implement a service, you must derive a class from
BaseRequestHandler and redefine its handle() method.  You can then run
various versions of the service by combining one of the server classes
with your request handler class.

The request handler class must be different for datagram or stream
68 69
services.  This can be hidden by using the request handler
subclasses StreamRequestHandler or DatagramRequestHandler.
Guido van Rossum's avatar
Guido van Rossum committed
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

Of course, you still have to use your head!

For instance, it makes no sense to use a forking server if the service
contains state in memory that can be modified by requests (since the
modifications in the child process would never reach the initial state
kept in the parent process and passed to each child).  In this case,
you can use a threading server, but you will probably have to use
locks to avoid two requests that come in nearly simultaneous to apply
conflicting changes to the server state.

On the other hand, if you are building e.g. an HTTP server, where all
data is stored externally (e.g. in the file system), a synchronous
class will essentially render the service "deaf" while one request is
being handled -- which may be for a very long time if a client is slow
to reqd all the data it has requested.  Here a threading or forking
server is appropriate.

In some cases, it may be appropriate to process part of a request
synchronously, but to finish processing in a forked child depending on
the request data.  This can be implemented by using a synchronous
91
server and doing an explicit fork in the request handler class
Guido van Rossum's avatar
Guido van Rossum committed
92 93 94 95 96 97 98 99 100
handle() method.

Another approach to handling multiple simultaneous requests in an
environment that supports neither threads nor fork (or where these are
too expensive or inappropriate for the service) is to maintain an
explicit table of partially finished requests and to use select() to
decide which request to work on next (or whether to handle a new
incoming request).  This is particularly important for stream services
where each client can potentially be connected for a long time (if
101
threads or subprocesses cannot be used).
Guido van Rossum's avatar
Guido van Rossum committed
102 103 104 105 106 107 108 109 110 111

Future work:
- Standard classes for Sun RPC (which uses either UDP or TCP)
- Standard mix-in classes to implement various authentication
  and encryption schemes
- Standard framework for select-based multiplexing

XXX Open problems:
- What to do with out-of-band data?

112 113 114 115 116 117 118 119
BaseServer:
- split generic "request" functionality out into BaseServer class.
  Copyright (C) 2000  Luke Kenneth Casson Leighton <lkcl@samba.org>

  example: read entries from a SQL database (requires overriding
  get_request() to return a table entry from the database).
  entry is processed by a RequestHandlerClass.

Guido van Rossum's avatar
Guido van Rossum committed
120 121
"""

122
# Author of the BaseServer patch: Luke Kenneth Casson Leighton
Guido van Rossum's avatar
Guido van Rossum committed
123

124 125 126 127 128 129
# XXX Warning!
# There is a test suite for this module, but it cannot be run by the
# standard regression test.
# To run it manually, run Lib/test/test_socketserver.py.

__version__ = "0.4"
Guido van Rossum's avatar
Guido van Rossum committed
130 131 132 133 134 135


import socket
import sys
import os

136 137
__all__ = ["TCPServer","UDPServer","ForkingUDPServer","ForkingTCPServer",
           "ThreadingUDPServer","ThreadingTCPServer","BaseRequestHandler",
138 139
           "StreamRequestHandler","DatagramRequestHandler",
           "ThreadingMixIn", "ForkingMixIn"]
140 141 142 143
if hasattr(socket, "AF_UNIX"):
    __all__.extend(["UnixStreamServer","UnixDatagramServer",
                    "ThreadingUnixStreamServer",
                    "ThreadingUnixDatagramServer"])
Guido van Rossum's avatar
Guido van Rossum committed
144

145
class BaseServer:
Guido van Rossum's avatar
Guido van Rossum committed
146

147
    """Base class for server classes.
Guido van Rossum's avatar
Guido van Rossum committed
148 149 150 151 152

    Methods for the caller:

    - __init__(server_address, RequestHandlerClass)
    - serve_forever()
153
    - handle_request()  # if you do not use serve_forever()
154
    - fileno() -> int   # for select()
Guido van Rossum's avatar
Guido van Rossum committed
155 156 157 158 159 160 161

    Methods that may be overridden:

    - server_bind()
    - server_activate()
    - get_request() -> request, client_address
    - verify_request(request, client_address)
162
    - server_close()
Guido van Rossum's avatar
Guido van Rossum committed
163
    - process_request(request, client_address)
164
    - close_request(request)
Guido van Rossum's avatar
Guido van Rossum committed
165 166 167 168 169 170 171 172 173 174 175
    - handle_error()

    Methods for derived classes:

    - finish_request(request, client_address)

    Class variables that may be overridden by derived classes or
    instances:

    - address_family
    - socket_type
176
    - allow_reuse_address
Guido van Rossum's avatar
Guido van Rossum committed
177 178 179 180 181 182 183 184 185

    Instance variables:

    - RequestHandlerClass
    - socket

    """

    def __init__(self, server_address, RequestHandlerClass):
186 187 188
        """Constructor.  May be extended, do not override."""
        self.server_address = server_address
        self.RequestHandlerClass = RequestHandlerClass
Guido van Rossum's avatar
Guido van Rossum committed
189 190

    def server_activate(self):
191
        """Called by constructor to activate the server.
Guido van Rossum's avatar
Guido van Rossum committed
192

193
        May be overridden.
Guido van Rossum's avatar
Guido van Rossum committed
194

195
        """
196
        pass
Guido van Rossum's avatar
Guido van Rossum committed
197 198

    def serve_forever(self):
199 200 201
        """Handle one request at a time until doomsday."""
        while 1:
            self.handle_request()
Guido van Rossum's avatar
Guido van Rossum committed
202 203 204 205 206 207 208 209 210 211 212 213 214

    # The distinction between handling, getting, processing and
    # 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
    # - 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;
    #   this constructor will handle the request all by itself

    def handle_request(self):
215
        """Handle one request, possibly blocking."""
216 217 218 219
        try:
            request, client_address = self.get_request()
        except socket.error:
            return
220 221 222 223 224
        if self.verify_request(request, client_address):
            try:
                self.process_request(request, client_address)
            except:
                self.handle_error(request, client_address)
225
                self.close_request(request)
Guido van Rossum's avatar
Guido van Rossum committed
226 227

    def verify_request(self, request, client_address):
228
        """Verify the request.  May be overridden.
Guido van Rossum's avatar
Guido van Rossum committed
229

230
        Return True if we should proceed with this request.
Guido van Rossum's avatar
Guido van Rossum committed
231

232
        """
233
        return True
Guido van Rossum's avatar
Guido van Rossum committed
234 235

    def process_request(self, request, client_address):
236
        """Call finish_request.
Guido van Rossum's avatar
Guido van Rossum committed
237

238
        Overridden by ForkingMixIn and ThreadingMixIn.
Guido van Rossum's avatar
Guido van Rossum committed
239

240 241
        """
        self.finish_request(request, client_address)
242
        self.close_request(request)
Guido van Rossum's avatar
Guido van Rossum committed
243

244 245 246 247 248 249 250 251
    def server_close(self):
        """Called to clean-up the server.

        May be overridden.

        """
        pass

Guido van Rossum's avatar
Guido van Rossum committed
252
    def finish_request(self, request, client_address):
253 254
        """Finish one request by instantiating RequestHandlerClass."""
        self.RequestHandlerClass(request, client_address, self)
Guido van Rossum's avatar
Guido van Rossum committed
255

256 257 258 259
    def close_request(self, request):
        """Called to clean up an individual request."""
        pass

Guido van Rossum's avatar
Guido van Rossum committed
260
    def handle_error(self, request, client_address):
261
        """Handle an error gracefully.  May be overridden.
Guido van Rossum's avatar
Guido van Rossum committed
262

263
        The default is to print a traceback and continue.
Guido van Rossum's avatar
Guido van Rossum committed
264

265 266 267 268 269
        """
        print '-'*40
        print 'Exception happened during processing of request from',
        print client_address
        import traceback
270
        traceback.print_exc() # XXX But this goes to stderr!
271
        print '-'*40
Guido van Rossum's avatar
Guido van Rossum committed
272 273


274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
class TCPServer(BaseServer):

    """Base class for various socket-based server classes.

    Defaults to synchronous IP stream (i.e., TCP).

    Methods for the caller:

    - __init__(server_address, RequestHandlerClass)
    - serve_forever()
    - handle_request()  # if you don't use serve_forever()
    - fileno() -> int   # for select()

    Methods that may be overridden:

    - server_bind()
    - server_activate()
    - get_request() -> request, client_address
    - verify_request(request, client_address)
    - process_request(request, client_address)
294
    - close_request(request)
295 296 297 298 299 300 301 302 303 304 305 306
    - handle_error()

    Methods for derived classes:

    - finish_request(request, client_address)

    Class variables that may be overridden by derived classes or
    instances:

    - address_family
    - socket_type
    - request_queue_size (only for stream sockets)
307
    - allow_reuse_address
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322

    Instance variables:

    - server_address
    - RequestHandlerClass
    - socket

    """

    address_family = socket.AF_INET

    socket_type = socket.SOCK_STREAM

    request_queue_size = 5

323
    allow_reuse_address = False
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374

    def __init__(self, server_address, RequestHandlerClass):
        """Constructor.  May be extended, do not override."""
        BaseServer.__init__(self, server_address, 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.

        May be overridden.

        """
        if self.allow_reuse_address:
            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.socket.bind(self.server_address)

    def server_activate(self):
        """Called by constructor to activate the server.

        May be overridden.

        """
        self.socket.listen(self.request_queue_size)

    def server_close(self):
        """Called to clean-up the server.

        May be overridden.

        """
        self.socket.close()

    def fileno(self):
        """Return socket file number.

        Interface required by select().

        """
        return self.socket.fileno()

    def get_request(self):
        """Get the request and client address from the socket.

        May be overridden.

        """
        return self.socket.accept()

375 376 377 378
    def close_request(self, request):
        """Called to clean up an individual request."""
        request.close()

379

Guido van Rossum's avatar
Guido van Rossum committed
380 381 382 383
class UDPServer(TCPServer):

    """UDP server class."""

384
    allow_reuse_address = False
385

Guido van Rossum's avatar
Guido van Rossum committed
386 387 388 389 390
    socket_type = socket.SOCK_DGRAM

    max_packet_size = 8192

    def get_request(self):
391 392 393 394 395 396
        data, client_addr = self.socket.recvfrom(self.max_packet_size)
        return (data, self.socket), client_addr

    def server_activate(self):
        # No need to call listen() for UDP.
        pass
Guido van Rossum's avatar
Guido van Rossum committed
397

398 399 400
    def close_request(self, request):
        # No need to close anything.
        pass
Guido van Rossum's avatar
Guido van Rossum committed
401 402 403 404 405 406

class ForkingMixIn:

    """Mix-in class to handle each request in a new process."""

    active_children = None
407
    max_children = 40
Guido van Rossum's avatar
Guido van Rossum committed
408 409

    def collect_children(self):
410 411
        """Internal routine to wait for died children."""
        while self.active_children:
412 413 414 415 416 417
            if len(self.active_children) < self.max_children:
                options = os.WNOHANG
            else:
                # If the maximum number of children are already
                # running, block while waiting for a child to exit
                options = 0
418
            try:
419
                pid, status = os.waitpid(0, options)
420 421
            except os.error:
                pid = None
422 423
            if not pid: break
            self.active_children.remove(pid)
Guido van Rossum's avatar
Guido van Rossum committed
424 425

    def process_request(self, request, client_address):
426 427 428 429 430 431 432 433
        """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)
434
            self.close_request(request)
435 436 437 438 439 440 441 442 443
            return
        else:
            # Child process.
            # This must never return, hence os._exit()!
            try:
                self.finish_request(request, client_address)
                os._exit(0)
            except:
                try:
444
                    self.handle_error(request, client_address)
445 446
                finally:
                    os._exit(1)
Guido van Rossum's avatar
Guido van Rossum committed
447 448 449 450 451


class ThreadingMixIn:
    """Mix-in class to handle each request in a new thread."""

452 453
    # Decides how threads will act upon termination of the
    # main process
Fred Drake's avatar
Fred Drake committed
454
    daemon_threads = False
455

456
    def process_request_thread(self, request, client_address):
457 458 459 460 461 462 463 464 465 466 467
        """Same as in BaseServer but as a thread.

        In addition, exception handling is done here.

        """
        try:
            self.finish_request(request, client_address)
            self.close_request(request)
        except:
            self.handle_error(request, client_address)
            self.close_request(request)
468

Guido van Rossum's avatar
Guido van Rossum committed
469
    def process_request(self, request, client_address):
470
        """Start a new thread to process the request."""
471
        import threading
472
        t = threading.Thread(target = self.process_request_thread,
473
                             args = (request, client_address))
474 475
        if self.daemon_threads:
            t.setDaemon (1)
476
        t.start()
Guido van Rossum's avatar
Guido van Rossum committed
477 478 479 480 481 482 483 484


class ForkingUDPServer(ForkingMixIn, UDPServer): pass
class ForkingTCPServer(ForkingMixIn, TCPServer): pass

class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass

485 486 487 488 489 490 491 492 493 494 495
if hasattr(socket, 'AF_UNIX'):

    class UnixStreamServer(TCPServer):
        address_family = socket.AF_UNIX

    class UnixDatagramServer(UDPServer):
        address_family = socket.AF_UNIX

    class ThreadingUnixStreamServer(ThreadingMixIn, UnixStreamServer): pass

    class ThreadingUnixDatagramServer(ThreadingMixIn, UnixDatagramServer): pass
Guido van Rossum's avatar
Guido van Rossum committed
496 497 498 499 500 501 502 503 504 505 506 507

class BaseRequestHandler:

    """Base class for request handler classes.

    This class is instantiated for each request to be handled.  The
    constructor sets the instance variables request, client_address
    and server, and then calls the handle() method.  To implement a
    specific service, all you need to do is to derive a class which
    defines a handle() method.

    The handle() method can find the request as self.request, the
508
    client address as self.client_address, and the server (in case it
Guido van Rossum's avatar
Guido van Rossum committed
509 510 511 512 513 514 515
    needs access to per-server information) as self.server.  Since a
    separate instance is created for each request, the handle() method
    can define arbitrary other instance variariables.

    """

    def __init__(self, request, client_address, server):
516 517 518 519 520 521 522 523 524
        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
Guido van Rossum's avatar
Guido van Rossum committed
525 526

    def setup(self):
527
        pass
Guido van Rossum's avatar
Guido van Rossum committed
528 529

    def handle(self):
530
        pass
Guido van Rossum's avatar
Guido van Rossum committed
531 532

    def finish(self):
533
        pass
Guido van Rossum's avatar
Guido van Rossum committed
534 535 536 537 538 539 540 541 542 543 544 545 546 547


# The following two classes make it possible to use the same service
# class for stream or datagram servers.
# Each class sets up these instance variables:
# - rfile: a file object from which receives the request is read
# - wfile: a file object to which the reply is written
# When the handle() method returns, wfile is flushed properly


class StreamRequestHandler(BaseRequestHandler):

    """Define self.rfile and self.wfile for stream sockets."""

548 549 550 551 552 553 554 555 556 557
    # Default buffer sizes for rfile, wfile.
    # We default rfile to buffered because otherwise it could be
    # really slow for large data (a getc() call per byte); we make
    # wfile unbuffered because (a) often after a write() we want to
    # read and we need to flush the line; (b) big writes to unbuffered
    # files are typically optimized by stdio even when big reads
    # aren't.
    rbufsize = -1
    wbufsize = 0

Guido van Rossum's avatar
Guido van Rossum committed
558
    def setup(self):
559
        self.connection = self.request
560 561
        self.rfile = self.connection.makefile('rb', self.rbufsize)
        self.wfile = self.connection.makefile('wb', self.wbufsize)
Guido van Rossum's avatar
Guido van Rossum committed
562 563

    def finish(self):
564 565
        if not self.wfile.closed:
            self.wfile.flush()
566 567
        self.wfile.close()
        self.rfile.close()
Guido van Rossum's avatar
Guido van Rossum committed
568 569 570 571


class DatagramRequestHandler(BaseRequestHandler):

572 573 574
    # XXX Regrettably, I cannot get this working on Linux;
    # s.recvfrom() doesn't return a meaningful client address.

Guido van Rossum's avatar
Guido van Rossum committed
575 576 577
    """Define self.rfile and self.wfile for datagram sockets."""

    def setup(self):
578 579 580 581
        try:
            from cStringIO import StringIO
        except ImportError:
            from StringIO import StringIO
582
        self.packet, self.socket = self.request
583 584
        self.rfile = StringIO(self.packet)
        self.wfile = StringIO()
Guido van Rossum's avatar
Guido van Rossum committed
585 586

    def finish(self):
587
        self.socket.sendto(self.wfile.getvalue(), self.client_address)