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