~pythonregexp2.7/python/issue2636-01

« back to all changes in this revision

Viewing changes to Lib/socketserver.py

  • Committer: Jeffrey C. "The TimeHorse" Jacobs
  • Date: 2008-06-09 14:37:21 UTC
  • mfrom: (39022.1.14 Regexp-2.6)
  • Revision ID: darklord@timehorse.com-20080609143721-bj0g1mwta28038da
Merged in changes from the core Regexp branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 <lkcl@samba.org>
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 select
134
 
import sys
135
 
import os
136
 
try:
137
 
    import threading
138
 
except ImportError:
139
 
    import dummy_threading as threading
140
 
 
141
 
__all__ = ["TCPServer","UDPServer","ForkingUDPServer","ForkingTCPServer",
142
 
           "ThreadingUDPServer","ThreadingTCPServer","BaseRequestHandler",
143
 
           "StreamRequestHandler","DatagramRequestHandler",
144
 
           "ThreadingMixIn", "ForkingMixIn"]
145
 
if hasattr(socket, "AF_UNIX"):
146
 
    __all__.extend(["UnixStreamServer","UnixDatagramServer",
147
 
                    "ThreadingUnixStreamServer",
148
 
                    "ThreadingUnixDatagramServer"])
149
 
 
150
 
class BaseServer:
151
 
 
152
 
    """Base class for server classes.
153
 
 
154
 
    Methods for the caller:
155
 
 
156
 
    - __init__(server_address, RequestHandlerClass)
157
 
    - serve_forever(poll_interval=0.5)
158
 
    - shutdown()
159
 
    - handle_request()  # if you do not use serve_forever()
160
 
    - fileno() -> int   # for select()
161
 
 
162
 
    Methods that may be overridden:
163
 
 
164
 
    - server_bind()
165
 
    - server_activate()
166
 
    - get_request() -> request, client_address
167
 
    - handle_timeout()
168
 
    - verify_request(request, client_address)
169
 
    - server_close()
170
 
    - process_request(request, client_address)
171
 
    - close_request(request)
172
 
    - handle_error()
173
 
 
174
 
    Methods for derived classes:
175
 
 
176
 
    - finish_request(request, client_address)
177
 
 
178
 
    Class variables that may be overridden by derived classes or
179
 
    instances:
180
 
 
181
 
    - timeout
182
 
    - address_family
183
 
    - socket_type
184
 
    - allow_reuse_address
185
 
 
186
 
    Instance variables:
187
 
 
188
 
    - RequestHandlerClass
189
 
    - socket
190
 
 
191
 
    """
192
 
 
193
 
    timeout = None
194
 
 
195
 
    def __init__(self, server_address, RequestHandlerClass):
196
 
        """Constructor.  May be extended, do not override."""
197
 
        self.server_address = server_address
198
 
        self.RequestHandlerClass = RequestHandlerClass
199
 
        self.__is_shut_down = threading.Event()
200
 
        self.__serving = False
201
 
 
202
 
    def server_activate(self):
203
 
        """Called by constructor to activate the server.
204
 
 
205
 
        May be overridden.
206
 
 
207
 
        """
208
 
        pass
209
 
 
210
 
    def serve_forever(self, poll_interval=0.5):
211
 
        """Handle one request at a time until shutdown.
212
 
 
213
 
        Polls for shutdown every poll_interval seconds. Ignores
214
 
        self.timeout. If you need to do periodic tasks, do them in
215
 
        another thread.
216
 
        """
217
 
        self.__serving = True
218
 
        self.__is_shut_down.clear()
219
 
        while self.__serving:
220
 
            # XXX: Consider using another file descriptor or
221
 
            # connecting to the socket to wake this up instead of
222
 
            # polling. Polling reduces our responsiveness to a
223
 
            # shutdown request and wastes cpu at all other times.
224
 
            r, w, e = select.select([self], [], [], poll_interval)
225
 
            if r:
226
 
                self._handle_request_noblock()
227
 
        self.__is_shut_down.set()
228
 
 
229
 
    def shutdown(self):
230
 
        """Stops the serve_forever loop.
231
 
 
232
 
        Blocks until the loop has finished. This must be called while
233
 
        serve_forever() is running in another thread, or it will
234
 
        deadlock.
235
 
        """
236
 
        self.__serving = False
237
 
        self.__is_shut_down.wait()
238
 
 
239
 
    # The distinction between handling, getting, processing and
240
 
    # finishing a request is fairly arbitrary.  Remember:
241
 
    #
242
 
    # - handle_request() is the top-level call.  It calls
243
 
    #   select, get_request(), verify_request() and process_request()
244
 
    # - get_request() is different for stream or datagram sockets
245
 
    # - process_request() is the place that may fork a new process
246
 
    #   or create a new thread to finish the request
247
 
    # - finish_request() instantiates the request handler class;
248
 
    #   this constructor will handle the request all by itself
249
 
 
250
 
    def handle_request(self):
251
 
        """Handle one request, possibly blocking.
252
 
 
253
 
        Respects self.timeout.
254
 
        """
255
 
        # Support people who used socket.settimeout() to escape
256
 
        # handle_request before self.timeout was available.
257
 
        timeout = self.socket.gettimeout()
258
 
        if timeout is None:
259
 
            timeout = self.timeout
260
 
        elif self.timeout is not None:
261
 
            timeout = min(timeout, self.timeout)
262
 
        fd_sets = select.select([self], [], [], timeout)
263
 
        if not fd_sets[0]:
264
 
            self.handle_timeout()
265
 
            return
266
 
        self._handle_request_noblock()
267
 
 
268
 
    def _handle_request_noblock(self):
269
 
        """Handle one request, without blocking.
270
 
 
271
 
        I assume that select.select has returned that the socket is
272
 
        readable before this function was called, so there should be
273
 
        no risk of blocking in get_request().
274
 
        """
275
 
        try:
276
 
            request, client_address = self.get_request()
277
 
        except socket.error:
278
 
            return
279
 
        if self.verify_request(request, client_address):
280
 
            try:
281
 
                self.process_request(request, client_address)
282
 
            except:
283
 
                self.handle_error(request, client_address)
284
 
                self.close_request(request)
285
 
 
286
 
    def handle_timeout(self):
287
 
        """Called if no new request arrives within self.timeout.
288
 
 
289
 
        Overridden by ForkingMixIn.
290
 
        """
291
 
        pass
292
 
 
293
 
    def verify_request(self, request, client_address):
294
 
        """Verify the request.  May be overridden.
295
 
 
296
 
        Return True if we should proceed with this request.
297
 
 
298
 
        """
299
 
        return True
300
 
 
301
 
    def process_request(self, request, client_address):
302
 
        """Call finish_request.
303
 
 
304
 
        Overridden by ForkingMixIn and ThreadingMixIn.
305
 
 
306
 
        """
307
 
        self.finish_request(request, client_address)
308
 
        self.close_request(request)
309
 
 
310
 
    def server_close(self):
311
 
        """Called to clean-up the server.
312
 
 
313
 
        May be overridden.
314
 
 
315
 
        """
316
 
        pass
317
 
 
318
 
    def finish_request(self, request, client_address):
319
 
        """Finish one request by instantiating RequestHandlerClass."""
320
 
        self.RequestHandlerClass(request, client_address, self)
321
 
 
322
 
    def close_request(self, request):
323
 
        """Called to clean up an individual request."""
324
 
        pass
325
 
 
326
 
    def handle_error(self, request, client_address):
327
 
        """Handle an error gracefully.  May be overridden.
328
 
 
329
 
        The default is to print a traceback and continue.
330
 
 
331
 
        """
332
 
        print '-'*40
333
 
        print 'Exception happened during processing of request from',
334
 
        print client_address
335
 
        import traceback
336
 
        traceback.print_exc() # XXX But this goes to stderr!
337
 
        print '-'*40
338
 
 
339
 
 
340
 
class TCPServer(BaseServer):
341
 
 
342
 
    """Base class for various socket-based server classes.
343
 
 
344
 
    Defaults to synchronous IP stream (i.e., TCP).
345
 
 
346
 
    Methods for the caller:
347
 
 
348
 
    - __init__(server_address, RequestHandlerClass, bind_and_activate=True)
349
 
    - serve_forever(poll_interval=0.5)
350
 
    - shutdown()
351
 
    - handle_request()  # if you don't use serve_forever()
352
 
    - fileno() -> int   # for select()
353
 
 
354
 
    Methods that may be overridden:
355
 
 
356
 
    - server_bind()
357
 
    - server_activate()
358
 
    - get_request() -> request, client_address
359
 
    - handle_timeout()
360
 
    - verify_request(request, client_address)
361
 
    - process_request(request, client_address)
362
 
    - close_request(request)
363
 
    - handle_error()
364
 
 
365
 
    Methods for derived classes:
366
 
 
367
 
    - finish_request(request, client_address)
368
 
 
369
 
    Class variables that may be overridden by derived classes or
370
 
    instances:
371
 
 
372
 
    - timeout
373
 
    - address_family
374
 
    - socket_type
375
 
    - request_queue_size (only for stream sockets)
376
 
    - allow_reuse_address
377
 
 
378
 
    Instance variables:
379
 
 
380
 
    - server_address
381
 
    - RequestHandlerClass
382
 
    - socket
383
 
 
384
 
    """
385
 
 
386
 
    address_family = socket.AF_INET
387
 
 
388
 
    socket_type = socket.SOCK_STREAM
389
 
 
390
 
    request_queue_size = 5
391
 
 
392
 
    allow_reuse_address = False
393
 
 
394
 
    def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
395
 
        """Constructor.  May be extended, do not override."""
396
 
        BaseServer.__init__(self, server_address, RequestHandlerClass)
397
 
        self.socket = socket.socket(self.address_family,
398
 
                                    self.socket_type)
399
 
        if bind_and_activate:
400
 
            self.server_bind()
401
 
            self.server_activate()
402
 
 
403
 
    def server_bind(self):
404
 
        """Called by constructor to bind the socket.
405
 
 
406
 
        May be overridden.
407
 
 
408
 
        """
409
 
        if self.allow_reuse_address:
410
 
            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
411
 
        self.socket.bind(self.server_address)
412
 
        self.server_address = self.socket.getsockname()
413
 
 
414
 
    def server_activate(self):
415
 
        """Called by constructor to activate the server.
416
 
 
417
 
        May be overridden.
418
 
 
419
 
        """
420
 
        self.socket.listen(self.request_queue_size)
421
 
 
422
 
    def server_close(self):
423
 
        """Called to clean-up the server.
424
 
 
425
 
        May be overridden.
426
 
 
427
 
        """
428
 
        self.socket.close()
429
 
 
430
 
    def fileno(self):
431
 
        """Return socket file number.
432
 
 
433
 
        Interface required by select().
434
 
 
435
 
        """
436
 
        return self.socket.fileno()
437
 
 
438
 
    def get_request(self):
439
 
        """Get the request and client address from the socket.
440
 
 
441
 
        May be overridden.
442
 
 
443
 
        """
444
 
        return self.socket.accept()
445
 
 
446
 
    def close_request(self, request):
447
 
        """Called to clean up an individual request."""
448
 
        request.close()
449
 
 
450
 
 
451
 
class UDPServer(TCPServer):
452
 
 
453
 
    """UDP server class."""
454
 
 
455
 
    allow_reuse_address = False
456
 
 
457
 
    socket_type = socket.SOCK_DGRAM
458
 
 
459
 
    max_packet_size = 8192
460
 
 
461
 
    def get_request(self):
462
 
        data, client_addr = self.socket.recvfrom(self.max_packet_size)
463
 
        return (data, self.socket), client_addr
464
 
 
465
 
    def server_activate(self):
466
 
        # No need to call listen() for UDP.
467
 
        pass
468
 
 
469
 
    def close_request(self, request):
470
 
        # No need to close anything.
471
 
        pass
472
 
 
473
 
class ForkingMixIn:
474
 
 
475
 
    """Mix-in class to handle each request in a new process."""
476
 
 
477
 
    timeout = 300
478
 
    active_children = None
479
 
    max_children = 40
480
 
 
481
 
    def collect_children(self):
482
 
        """Internal routine to wait for children that have exited."""
483
 
        if self.active_children is None: return
484
 
        while len(self.active_children) >= self.max_children:
485
 
            # XXX: This will wait for any child process, not just ones
486
 
            # spawned by this library. This could confuse other
487
 
            # libraries that expect to be able to wait for their own
488
 
            # children.
489
 
            try:
490
 
                pid, status = os.waitpid(0, options=0)
491
 
            except os.error:
492
 
                pid = None
493
 
            if pid not in self.active_children: continue
494
 
            self.active_children.remove(pid)
495
 
 
496
 
        # XXX: This loop runs more system calls than it ought
497
 
        # to. There should be a way to put the active_children into a
498
 
        # process group and then use os.waitpid(-pgid) to wait for any
499
 
        # of that set, but I couldn't find a way to allocate pgids
500
 
        # that couldn't collide.
501
 
        for child in self.active_children:
502
 
            try:
503
 
                pid, status = os.waitpid(child, os.WNOHANG)
504
 
            except os.error:
505
 
                pid = None
506
 
            if not pid: continue
507
 
            try:
508
 
                self.active_children.remove(pid)
509
 
            except ValueError, e:
510
 
                raise ValueError('%s. x=%d and list=%r' % (e.message, pid,
511
 
                                                           self.active_children))
512
 
 
513
 
    def handle_timeout(self):
514
 
        """Wait for zombies after self.timeout seconds of inactivity.
515
 
 
516
 
        May be extended, do not override.
517
 
        """
518
 
        self.collect_children()
519
 
 
520
 
    def process_request(self, request, client_address):
521
 
        """Fork a new subprocess to process the request."""
522
 
        self.collect_children()
523
 
        pid = os.fork()
524
 
        if pid:
525
 
            # Parent process
526
 
            if self.active_children is None:
527
 
                self.active_children = []
528
 
            self.active_children.append(pid)
529
 
            self.close_request(request)
530
 
            return
531
 
        else:
532
 
            # Child process.
533
 
            # This must never return, hence os._exit()!
534
 
            try:
535
 
                self.finish_request(request, client_address)
536
 
                os._exit(0)
537
 
            except:
538
 
                try:
539
 
                    self.handle_error(request, client_address)
540
 
                finally:
541
 
                    os._exit(1)
542
 
 
543
 
 
544
 
class ThreadingMixIn:
545
 
    """Mix-in class to handle each request in a new thread."""
546
 
 
547
 
    # Decides how threads will act upon termination of the
548
 
    # main process
549
 
    daemon_threads = False
550
 
 
551
 
    def process_request_thread(self, request, client_address):
552
 
        """Same as in BaseServer but as a thread.
553
 
 
554
 
        In addition, exception handling is done here.
555
 
 
556
 
        """
557
 
        try:
558
 
            self.finish_request(request, client_address)
559
 
            self.close_request(request)
560
 
        except:
561
 
            self.handle_error(request, client_address)
562
 
            self.close_request(request)
563
 
 
564
 
    def process_request(self, request, client_address):
565
 
        """Start a new thread to process the request."""
566
 
        t = threading.Thread(target = self.process_request_thread,
567
 
                             args = (request, client_address))
568
 
        if self.daemon_threads:
569
 
            t.setDaemon (1)
570
 
        t.start()
571
 
 
572
 
 
573
 
class ForkingUDPServer(ForkingMixIn, UDPServer): pass
574
 
class ForkingTCPServer(ForkingMixIn, TCPServer): pass
575
 
 
576
 
class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
577
 
class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
578
 
 
579
 
if hasattr(socket, 'AF_UNIX'):
580
 
 
581
 
    class UnixStreamServer(TCPServer):
582
 
        address_family = socket.AF_UNIX
583
 
 
584
 
    class UnixDatagramServer(UDPServer):
585
 
        address_family = socket.AF_UNIX
586
 
 
587
 
    class ThreadingUnixStreamServer(ThreadingMixIn, UnixStreamServer): pass
588
 
 
589
 
    class ThreadingUnixDatagramServer(ThreadingMixIn, UnixDatagramServer): pass
590
 
 
591
 
class BaseRequestHandler:
592
 
 
593
 
    """Base class for request handler classes.
594
 
 
595
 
    This class is instantiated for each request to be handled.  The
596
 
    constructor sets the instance variables request, client_address
597
 
    and server, and then calls the handle() method.  To implement a
598
 
    specific service, all you need to do is to derive a class which
599
 
    defines a handle() method.
600
 
 
601
 
    The handle() method can find the request as self.request, the
602
 
    client address as self.client_address, and the server (in case it
603
 
    needs access to per-server information) as self.server.  Since a
604
 
    separate instance is created for each request, the handle() method
605
 
    can define arbitrary other instance variariables.
606
 
 
607
 
    """
608
 
 
609
 
    def __init__(self, request, client_address, server):
610
 
        self.request = request
611
 
        self.client_address = client_address
612
 
        self.server = server
613
 
        try:
614
 
            self.setup()
615
 
            self.handle()
616
 
            self.finish()
617
 
        finally:
618
 
            sys.exc_traceback = None    # Help garbage collection
619
 
 
620
 
    def setup(self):
621
 
        pass
622
 
 
623
 
    def handle(self):
624
 
        pass
625
 
 
626
 
    def finish(self):
627
 
        pass
628
 
 
629
 
 
630
 
# The following two classes make it possible to use the same service
631
 
# class for stream or datagram servers.
632
 
# Each class sets up these instance variables:
633
 
# - rfile: a file object from which receives the request is read
634
 
# - wfile: a file object to which the reply is written
635
 
# When the handle() method returns, wfile is flushed properly
636
 
 
637
 
 
638
 
class StreamRequestHandler(BaseRequestHandler):
639
 
 
640
 
    """Define self.rfile and self.wfile for stream sockets."""
641
 
 
642
 
    # Default buffer sizes for rfile, wfile.
643
 
    # We default rfile to buffered because otherwise it could be
644
 
    # really slow for large data (a getc() call per byte); we make
645
 
    # wfile unbuffered because (a) often after a write() we want to
646
 
    # read and we need to flush the line; (b) big writes to unbuffered
647
 
    # files are typically optimized by stdio even when big reads
648
 
    # aren't.
649
 
    rbufsize = -1
650
 
    wbufsize = 0
651
 
 
652
 
    def setup(self):
653
 
        self.connection = self.request
654
 
        self.rfile = self.connection.makefile('rb', self.rbufsize)
655
 
        self.wfile = self.connection.makefile('wb', self.wbufsize)
656
 
 
657
 
    def finish(self):
658
 
        if not self.wfile.closed:
659
 
            self.wfile.flush()
660
 
        self.wfile.close()
661
 
        self.rfile.close()
662
 
 
663
 
 
664
 
class DatagramRequestHandler(BaseRequestHandler):
665
 
 
666
 
    # XXX Regrettably, I cannot get this working on Linux;
667
 
    # s.recvfrom() doesn't return a meaningful client address.
668
 
 
669
 
    """Define self.rfile and self.wfile for datagram sockets."""
670
 
 
671
 
    def setup(self):
672
 
        try:
673
 
            from cStringIO import StringIO
674
 
        except ImportError:
675
 
            from StringIO import StringIO
676
 
        self.packet, self.socket = self.request
677
 
        self.rfile = StringIO(self.packet)
678
 
        self.wfile = StringIO()
679
 
 
680
 
    def finish(self):
681
 
        self.socket.sendto(self.wfile.getvalue(), self.client_address)