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 saves 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 a selector 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
108 XXX Open problems:
109 - What to do with out-of-band data?
110
111 BaseServer:
112 - split generic "request" functionality out into BaseServer class.
113 Copyright (C) 2000 Luke Kenneth Casson Leighton <lkcl@samba.org>
114
115 example: read entries from a SQL database (requires overriding
116 get_request() to return a table entry from the database).
117 entry is processed by a RequestHandlerClass.
118
119 """
120
121 # Author of the BaseServer patch: Luke Kenneth Casson Leighton
122
123 __version__ = "0.4"
124
125
126 import socket
127 import selectors
128 import os
129 import sys
130 import threading
131 from io import BufferedIOBase
132 from time import monotonic as time
133
134 __all__ = ["BaseServer", "TCPServer", "UDPServer",
135 "ThreadingUDPServer", "ThreadingTCPServer",
136 "BaseRequestHandler", "StreamRequestHandler",
137 "DatagramRequestHandler", "ThreadingMixIn"]
138 if hasattr(os, "fork"):
139 __all__.extend(["ForkingUDPServer","ForkingTCPServer", "ForkingMixIn"])
140 if hasattr(socket, "AF_UNIX"):
141 __all__.extend(["UnixStreamServer","UnixDatagramServer",
142 "ThreadingUnixStreamServer",
143 "ThreadingUnixDatagramServer"])
144
145 # poll/select have the advantage of not requiring any extra file descriptor,
146 # contrarily to epoll/kqueue (also, they require a single syscall).
147 if hasattr(selectors, 'PollSelector'):
148 _ServerSelector = selectors.PollSelector
149 else:
150 _ServerSelector = selectors.SelectSelector
151
152
153 class ESC[4;38;5;81mBaseServer:
154
155 """Base class for server classes.
156
157 Methods for the caller:
158
159 - __init__(server_address, RequestHandlerClass)
160 - serve_forever(poll_interval=0.5)
161 - shutdown()
162 - handle_request() # if you do not use serve_forever()
163 - fileno() -> int # for selector
164
165 Methods that may be overridden:
166
167 - server_bind()
168 - server_activate()
169 - get_request() -> request, client_address
170 - handle_timeout()
171 - verify_request(request, client_address)
172 - server_close()
173 - process_request(request, client_address)
174 - shutdown_request(request)
175 - close_request(request)
176 - service_actions()
177 - handle_error()
178
179 Methods for derived classes:
180
181 - finish_request(request, client_address)
182
183 Class variables that may be overridden by derived classes or
184 instances:
185
186 - timeout
187 - address_family
188 - socket_type
189 - allow_reuse_address
190 - allow_reuse_port
191
192 Instance variables:
193
194 - RequestHandlerClass
195 - socket
196
197 """
198
199 timeout = None
200
201 def __init__(self, server_address, RequestHandlerClass):
202 """Constructor. May be extended, do not override."""
203 self.server_address = server_address
204 self.RequestHandlerClass = RequestHandlerClass
205 self.__is_shut_down = threading.Event()
206 self.__shutdown_request = False
207
208 def server_activate(self):
209 """Called by constructor to activate the server.
210
211 May be overridden.
212
213 """
214 pass
215
216 def serve_forever(self, poll_interval=0.5):
217 """Handle one request at a time until shutdown.
218
219 Polls for shutdown every poll_interval seconds. Ignores
220 self.timeout. If you need to do periodic tasks, do them in
221 another thread.
222 """
223 self.__is_shut_down.clear()
224 try:
225 # XXX: Consider using another file descriptor or connecting to the
226 # socket to wake this up instead of polling. Polling reduces our
227 # responsiveness to a shutdown request and wastes cpu at all other
228 # times.
229 with _ServerSelector() as selector:
230 selector.register(self, selectors.EVENT_READ)
231
232 while not self.__shutdown_request:
233 ready = selector.select(poll_interval)
234 # bpo-35017: shutdown() called during select(), exit immediately.
235 if self.__shutdown_request:
236 break
237 if ready:
238 self._handle_request_noblock()
239
240 self.service_actions()
241 finally:
242 self.__shutdown_request = False
243 self.__is_shut_down.set()
244
245 def shutdown(self):
246 """Stops the serve_forever loop.
247
248 Blocks until the loop has finished. This must be called while
249 serve_forever() is running in another thread, or it will
250 deadlock.
251 """
252 self.__shutdown_request = True
253 self.__is_shut_down.wait()
254
255 def service_actions(self):
256 """Called by the serve_forever() loop.
257
258 May be overridden by a subclass / Mixin to implement any code that
259 needs to be run during the loop.
260 """
261 pass
262
263 # The distinction between handling, getting, processing and finishing a
264 # request is fairly arbitrary. Remember:
265 #
266 # - handle_request() is the top-level call. It calls selector.select(),
267 # get_request(), verify_request() and process_request()
268 # - get_request() is different for stream or datagram sockets
269 # - process_request() is the place that may fork a new process or create a
270 # new thread to finish the request
271 # - finish_request() instantiates the request handler class; this
272 # constructor will handle the request all by itself
273
274 def handle_request(self):
275 """Handle one request, possibly blocking.
276
277 Respects self.timeout.
278 """
279 # Support people who used socket.settimeout() to escape
280 # handle_request before self.timeout was available.
281 timeout = self.socket.gettimeout()
282 if timeout is None:
283 timeout = self.timeout
284 elif self.timeout is not None:
285 timeout = min(timeout, self.timeout)
286 if timeout is not None:
287 deadline = time() + timeout
288
289 # Wait until a request arrives or the timeout expires - the loop is
290 # necessary to accommodate early wakeups due to EINTR.
291 with _ServerSelector() as selector:
292 selector.register(self, selectors.EVENT_READ)
293
294 while True:
295 ready = selector.select(timeout)
296 if ready:
297 return self._handle_request_noblock()
298 else:
299 if timeout is not None:
300 timeout = deadline - time()
301 if timeout < 0:
302 return self.handle_timeout()
303
304 def _handle_request_noblock(self):
305 """Handle one request, without blocking.
306
307 I assume that selector.select() has returned that the socket is
308 readable before this function was called, so there should be no risk of
309 blocking in get_request().
310 """
311 try:
312 request, client_address = self.get_request()
313 except OSError:
314 return
315 if self.verify_request(request, client_address):
316 try:
317 self.process_request(request, client_address)
318 except Exception:
319 self.handle_error(request, client_address)
320 self.shutdown_request(request)
321 except:
322 self.shutdown_request(request)
323 raise
324 else:
325 self.shutdown_request(request)
326
327 def handle_timeout(self):
328 """Called if no new request arrives within self.timeout.
329
330 Overridden by ForkingMixIn.
331 """
332 pass
333
334 def verify_request(self, request, client_address):
335 """Verify the request. May be overridden.
336
337 Return True if we should proceed with this request.
338
339 """
340 return True
341
342 def process_request(self, request, client_address):
343 """Call finish_request.
344
345 Overridden by ForkingMixIn and ThreadingMixIn.
346
347 """
348 self.finish_request(request, client_address)
349 self.shutdown_request(request)
350
351 def server_close(self):
352 """Called to clean-up the server.
353
354 May be overridden.
355
356 """
357 pass
358
359 def finish_request(self, request, client_address):
360 """Finish one request by instantiating RequestHandlerClass."""
361 self.RequestHandlerClass(request, client_address, self)
362
363 def shutdown_request(self, request):
364 """Called to shutdown and close an individual request."""
365 self.close_request(request)
366
367 def close_request(self, request):
368 """Called to clean up an individual request."""
369 pass
370
371 def handle_error(self, request, client_address):
372 """Handle an error gracefully. May be overridden.
373
374 The default is to print a traceback and continue.
375
376 """
377 print('-'*40, file=sys.stderr)
378 print('Exception occurred during processing of request from',
379 client_address, file=sys.stderr)
380 import traceback
381 traceback.print_exc()
382 print('-'*40, file=sys.stderr)
383
384 def __enter__(self):
385 return self
386
387 def __exit__(self, *args):
388 self.server_close()
389
390
391 class ESC[4;38;5;81mTCPServer(ESC[4;38;5;149mBaseServer):
392
393 """Base class for various socket-based server classes.
394
395 Defaults to synchronous IP stream (i.e., TCP).
396
397 Methods for the caller:
398
399 - __init__(server_address, RequestHandlerClass, bind_and_activate=True)
400 - serve_forever(poll_interval=0.5)
401 - shutdown()
402 - handle_request() # if you don't use serve_forever()
403 - fileno() -> int # for selector
404
405 Methods that may be overridden:
406
407 - server_bind()
408 - server_activate()
409 - get_request() -> request, client_address
410 - handle_timeout()
411 - verify_request(request, client_address)
412 - process_request(request, client_address)
413 - shutdown_request(request)
414 - close_request(request)
415 - handle_error()
416
417 Methods for derived classes:
418
419 - finish_request(request, client_address)
420
421 Class variables that may be overridden by derived classes or
422 instances:
423
424 - timeout
425 - address_family
426 - socket_type
427 - request_queue_size (only for stream sockets)
428 - allow_reuse_address
429 - allow_reuse_port
430
431 Instance variables:
432
433 - server_address
434 - RequestHandlerClass
435 - socket
436
437 """
438
439 address_family = socket.AF_INET
440
441 socket_type = socket.SOCK_STREAM
442
443 request_queue_size = 5
444
445 allow_reuse_address = False
446
447 allow_reuse_port = False
448
449 def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
450 """Constructor. May be extended, do not override."""
451 BaseServer.__init__(self, server_address, RequestHandlerClass)
452 self.socket = socket.socket(self.address_family,
453 self.socket_type)
454 if bind_and_activate:
455 try:
456 self.server_bind()
457 self.server_activate()
458 except:
459 self.server_close()
460 raise
461
462 def server_bind(self):
463 """Called by constructor to bind the socket.
464
465 May be overridden.
466
467 """
468 if self.allow_reuse_address and hasattr(socket, "SO_REUSEADDR"):
469 self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
470 if self.allow_reuse_port and hasattr(socket, "SO_REUSEPORT"):
471 self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
472 self.socket.bind(self.server_address)
473 self.server_address = self.socket.getsockname()
474
475 def server_activate(self):
476 """Called by constructor to activate the server.
477
478 May be overridden.
479
480 """
481 self.socket.listen(self.request_queue_size)
482
483 def server_close(self):
484 """Called to clean-up the server.
485
486 May be overridden.
487
488 """
489 self.socket.close()
490
491 def fileno(self):
492 """Return socket file number.
493
494 Interface required by selector.
495
496 """
497 return self.socket.fileno()
498
499 def get_request(self):
500 """Get the request and client address from the socket.
501
502 May be overridden.
503
504 """
505 return self.socket.accept()
506
507 def shutdown_request(self, request):
508 """Called to shutdown and close an individual request."""
509 try:
510 #explicitly shutdown. socket.close() merely releases
511 #the socket and waits for GC to perform the actual close.
512 request.shutdown(socket.SHUT_WR)
513 except OSError:
514 pass #some platforms may raise ENOTCONN here
515 self.close_request(request)
516
517 def close_request(self, request):
518 """Called to clean up an individual request."""
519 request.close()
520
521
522 class ESC[4;38;5;81mUDPServer(ESC[4;38;5;149mTCPServer):
523
524 """UDP server class."""
525
526 allow_reuse_address = False
527
528 allow_reuse_port = False
529
530 socket_type = socket.SOCK_DGRAM
531
532 max_packet_size = 8192
533
534 def get_request(self):
535 data, client_addr = self.socket.recvfrom(self.max_packet_size)
536 return (data, self.socket), client_addr
537
538 def server_activate(self):
539 # No need to call listen() for UDP.
540 pass
541
542 def shutdown_request(self, request):
543 # No need to shutdown anything.
544 self.close_request(request)
545
546 def close_request(self, request):
547 # No need to close anything.
548 pass
549
550 if hasattr(os, "fork"):
551 class ESC[4;38;5;81mForkingMixIn:
552 """Mix-in class to handle each request in a new process."""
553
554 timeout = 300
555 active_children = None
556 max_children = 40
557 # If true, server_close() waits until all child processes complete.
558 block_on_close = True
559
560 def collect_children(self, *, blocking=False):
561 """Internal routine to wait for children that have exited."""
562 if self.active_children is None:
563 return
564
565 # If we're above the max number of children, wait and reap them until
566 # we go back below threshold. Note that we use waitpid(-1) below to be
567 # able to collect children in size(<defunct children>) syscalls instead
568 # of size(<children>): the downside is that this might reap children
569 # which we didn't spawn, which is why we only resort to this when we're
570 # above max_children.
571 while len(self.active_children) >= self.max_children:
572 try:
573 pid, _ = os.waitpid(-1, 0)
574 self.active_children.discard(pid)
575 except ChildProcessError:
576 # we don't have any children, we're done
577 self.active_children.clear()
578 except OSError:
579 break
580
581 # Now reap all defunct children.
582 for pid in self.active_children.copy():
583 try:
584 flags = 0 if blocking else os.WNOHANG
585 pid, _ = os.waitpid(pid, flags)
586 # if the child hasn't exited yet, pid will be 0 and ignored by
587 # discard() below
588 self.active_children.discard(pid)
589 except ChildProcessError:
590 # someone else reaped it
591 self.active_children.discard(pid)
592 except OSError:
593 pass
594
595 def handle_timeout(self):
596 """Wait for zombies after self.timeout seconds of inactivity.
597
598 May be extended, do not override.
599 """
600 self.collect_children()
601
602 def service_actions(self):
603 """Collect the zombie child processes regularly in the ForkingMixIn.
604
605 service_actions is called in the BaseServer's serve_forever loop.
606 """
607 self.collect_children()
608
609 def process_request(self, request, client_address):
610 """Fork a new subprocess to process the request."""
611 pid = os.fork()
612 if pid:
613 # Parent process
614 if self.active_children is None:
615 self.active_children = set()
616 self.active_children.add(pid)
617 self.close_request(request)
618 return
619 else:
620 # Child process.
621 # This must never return, hence os._exit()!
622 status = 1
623 try:
624 self.finish_request(request, client_address)
625 status = 0
626 except Exception:
627 self.handle_error(request, client_address)
628 finally:
629 try:
630 self.shutdown_request(request)
631 finally:
632 os._exit(status)
633
634 def server_close(self):
635 super().server_close()
636 self.collect_children(blocking=self.block_on_close)
637
638
639 class ESC[4;38;5;81m_Threads(ESC[4;38;5;149mlist):
640 """
641 Joinable list of all non-daemon threads.
642 """
643 def append(self, thread):
644 self.reap()
645 if thread.daemon:
646 return
647 super().append(thread)
648
649 def pop_all(self):
650 self[:], result = [], self[:]
651 return result
652
653 def join(self):
654 for thread in self.pop_all():
655 thread.join()
656
657 def reap(self):
658 self[:] = (thread for thread in self if thread.is_alive())
659
660
661 class ESC[4;38;5;81m_NoThreads:
662 """
663 Degenerate version of _Threads.
664 """
665 def append(self, thread):
666 pass
667
668 def join(self):
669 pass
670
671
672 class ESC[4;38;5;81mThreadingMixIn:
673 """Mix-in class to handle each request in a new thread."""
674
675 # Decides how threads will act upon termination of the
676 # main process
677 daemon_threads = False
678 # If true, server_close() waits until all non-daemonic threads terminate.
679 block_on_close = True
680 # Threads object
681 # used by server_close() to wait for all threads completion.
682 _threads = _NoThreads()
683
684 def process_request_thread(self, request, client_address):
685 """Same as in BaseServer but as a thread.
686
687 In addition, exception handling is done here.
688
689 """
690 try:
691 self.finish_request(request, client_address)
692 except Exception:
693 self.handle_error(request, client_address)
694 finally:
695 self.shutdown_request(request)
696
697 def process_request(self, request, client_address):
698 """Start a new thread to process the request."""
699 if self.block_on_close:
700 vars(self).setdefault('_threads', _Threads())
701 t = threading.Thread(target = self.process_request_thread,
702 args = (request, client_address))
703 t.daemon = self.daemon_threads
704 self._threads.append(t)
705 t.start()
706
707 def server_close(self):
708 super().server_close()
709 self._threads.join()
710
711
712 if hasattr(os, "fork"):
713 class ESC[4;38;5;81mForkingUDPServer(ESC[4;38;5;149mForkingMixIn, ESC[4;38;5;149mUDPServer): pass
714 class ESC[4;38;5;81mForkingTCPServer(ESC[4;38;5;149mForkingMixIn, ESC[4;38;5;149mTCPServer): pass
715
716 class ESC[4;38;5;81mThreadingUDPServer(ESC[4;38;5;149mThreadingMixIn, ESC[4;38;5;149mUDPServer): pass
717 class ESC[4;38;5;81mThreadingTCPServer(ESC[4;38;5;149mThreadingMixIn, ESC[4;38;5;149mTCPServer): pass
718
719 if hasattr(socket, 'AF_UNIX'):
720
721 class ESC[4;38;5;81mUnixStreamServer(ESC[4;38;5;149mTCPServer):
722 address_family = socket.AF_UNIX
723
724 class ESC[4;38;5;81mUnixDatagramServer(ESC[4;38;5;149mUDPServer):
725 address_family = socket.AF_UNIX
726
727 class ESC[4;38;5;81mThreadingUnixStreamServer(ESC[4;38;5;149mThreadingMixIn, ESC[4;38;5;149mUnixStreamServer): pass
728
729 class ESC[4;38;5;81mThreadingUnixDatagramServer(ESC[4;38;5;149mThreadingMixIn, ESC[4;38;5;149mUnixDatagramServer): pass
730
731 class ESC[4;38;5;81mBaseRequestHandler:
732
733 """Base class for request handler classes.
734
735 This class is instantiated for each request to be handled. The
736 constructor sets the instance variables request, client_address
737 and server, and then calls the handle() method. To implement a
738 specific service, all you need to do is to derive a class which
739 defines a handle() method.
740
741 The handle() method can find the request as self.request, the
742 client address as self.client_address, and the server (in case it
743 needs access to per-server information) as self.server. Since a
744 separate instance is created for each request, the handle() method
745 can define other arbitrary instance variables.
746
747 """
748
749 def __init__(self, request, client_address, server):
750 self.request = request
751 self.client_address = client_address
752 self.server = server
753 self.setup()
754 try:
755 self.handle()
756 finally:
757 self.finish()
758
759 def setup(self):
760 pass
761
762 def handle(self):
763 pass
764
765 def finish(self):
766 pass
767
768
769 # The following two classes make it possible to use the same service
770 # class for stream or datagram servers.
771 # Each class sets up these instance variables:
772 # - rfile: a file object from which receives the request is read
773 # - wfile: a file object to which the reply is written
774 # When the handle() method returns, wfile is flushed properly
775
776
777 class ESC[4;38;5;81mStreamRequestHandler(ESC[4;38;5;149mBaseRequestHandler):
778
779 """Define self.rfile and self.wfile for stream sockets."""
780
781 # Default buffer sizes for rfile, wfile.
782 # We default rfile to buffered because otherwise it could be
783 # really slow for large data (a getc() call per byte); we make
784 # wfile unbuffered because (a) often after a write() we want to
785 # read and we need to flush the line; (b) big writes to unbuffered
786 # files are typically optimized by stdio even when big reads
787 # aren't.
788 rbufsize = -1
789 wbufsize = 0
790
791 # A timeout to apply to the request socket, if not None.
792 timeout = None
793
794 # Disable nagle algorithm for this socket, if True.
795 # Use only when wbufsize != 0, to avoid small packets.
796 disable_nagle_algorithm = False
797
798 def setup(self):
799 self.connection = self.request
800 if self.timeout is not None:
801 self.connection.settimeout(self.timeout)
802 if self.disable_nagle_algorithm:
803 self.connection.setsockopt(socket.IPPROTO_TCP,
804 socket.TCP_NODELAY, True)
805 self.rfile = self.connection.makefile('rb', self.rbufsize)
806 if self.wbufsize == 0:
807 self.wfile = _SocketWriter(self.connection)
808 else:
809 self.wfile = self.connection.makefile('wb', self.wbufsize)
810
811 def finish(self):
812 if not self.wfile.closed:
813 try:
814 self.wfile.flush()
815 except socket.error:
816 # A final socket error may have occurred here, such as
817 # the local error ECONNABORTED.
818 pass
819 self.wfile.close()
820 self.rfile.close()
821
822 class ESC[4;38;5;81m_SocketWriter(ESC[4;38;5;149mBufferedIOBase):
823 """Simple writable BufferedIOBase implementation for a socket
824
825 Does not hold data in a buffer, avoiding any need to call flush()."""
826
827 def __init__(self, sock):
828 self._sock = sock
829
830 def writable(self):
831 return True
832
833 def write(self, b):
834 self._sock.sendall(b)
835 with memoryview(b) as view:
836 return view.nbytes
837
838 def fileno(self):
839 return self._sock.fileno()
840
841 class ESC[4;38;5;81mDatagramRequestHandler(ESC[4;38;5;149mBaseRequestHandler):
842
843 """Define self.rfile and self.wfile for datagram sockets."""
844
845 def setup(self):
846 from io import BytesIO
847 self.packet, self.socket = self.request
848 self.rfile = BytesIO(self.packet)
849 self.wfile = BytesIO()
850
851 def finish(self):
852 self.socket.sendto(self.wfile.getvalue(), self.client_address)