Commits

clach04 committed 32012dd

Python 2.5 and earlier support for threading server, based on py2.6 SocketServer shutdown code.

Comments (0)

Files changed (1)

 import sys
 import socket
 import SocketServer
+import threading
+import select
 import logging
 import glob
 import errno
             os.chdir(current_dir)
 
 
-class MyTCPServer(SocketServer.TCPServer):
+class StoppableTCPServer(SocketServer.ThreadingTCPServer):
+   def __init__(self, address_tuple, handler):
+      SocketServer.ThreadingTCPServer.__init__(self, address_tuple, handler)
+      self.__is_shut_down = threading.Event()
+      self.__shutdown_request = False
+ 
+   def serve_forever(self, poll_interval=0.5):
+      """Handle one request at a time until shutdown.
+ 
+         Polls for shutdown every poll_interval seconds. Ignores
+         self.timeout. If you need to do periodic tasks, do them in
+         another thread.
+      """
+      self.__is_shut_down.clear()
+      try:
+         while not self.__shutdown_request:
+            r, w, e = select.select([self], [], [], poll_interval)
+            if self in r:
+               self._handle_request_noblock()
+      finally:
+         self.__shutdown_request = False
+         self.__is_shut_down.set()
+ 
+   def shutdown(self):
+      """Stops the serve_forever loop.
+ 
+         Blocks until the loop has finished. This must be called while
+         serve_forever() is running in another thread, or it will
+         deadlock.
+      """
+      self.__shutdown_request = True
+      self.__is_shut_down.wait()
+ 
+   def _handle_request_noblock(self):
+      """Handle one request, without blocking.
+ 
+         I assume that select.select has returned that the socket is
+         readable before this function was called, so there should be
+         no risk of blocking in get_request().
+      """
+      try:
+         request, client_address = self.get_request()
+      except socket.error:
+         return
+      if self.verify_request(request, client_address):
+         try:
+            self.process_request(request, client_address)
+         except:
+            self.handle_error(request, client_address)
+            self.close_request(request)
+
+if hasattr(SocketServer.TCPServer, 'shutdown'):
+    MyBaseTCPServer = SocketServer.TCPServer
+else:
+    # CPython 2.5 or older
+    MyBaseTCPServer = StoppableTCPServer
+
+class MyTCPServer(MyBaseTCPServer):
     """Ensure CTRL-C followed by restart works without:
              socket.error: [Errno 98] Address already in use
     """
     def __init__(self, *args, **kwargs):
         self.allow_reuse_address = 1
-        SocketServer.TCPServer.__init__(self, *args, **kwargs)
+        MyBaseTCPServer.__init__(self, *args, **kwargs)
 
 
 class MyThreadedTCPServer(SocketServer.ThreadingMixIn, MyTCPServer):