How to stop BaseHTTPServer.serve_forever() in a BaseHTTPRequestHandler subclass?

后端 未结 10 1191
渐次进展
渐次进展 2020-12-01 04:53

I am running my HTTPServer in a separate thread (using the threading module which has no way to stop threads...) and want to stop serving requests when the main

相关标签:
10条回答
  • 2020-12-01 05:31

    The event-loops ends on SIGTERM, Ctrl+C or when shutdown() is called.

    server_close() must be called after server_forever() to close the listening socket.

    import http.server
    
    class StoppableHTTPServer(http.server.HTTPServer):
        def run(self):
            try:
                self.serve_forever()
            except KeyboardInterrupt:
                pass
            finally:
                # Clean-up server (close socket, etc.)
                self.server_close()
    

    Simple server stoppable with user action (SIGTERM, Ctrl+C, ...):

    server = StoppableHTTPServer(("127.0.0.1", 8080),
                                 http.server.BaseHTTPRequestHandler)
    server.run()
    

    Server running in a thread:

    import threading
    
    server = StoppableHTTPServer(("127.0.0.1", 8080),
                                 http.server.BaseHTTPRequestHandler)
    
    # Start processing requests
    thread = threading.Thread(None, server.run)
    thread.start()
    
    # ... do things ...
    
    # Shutdown server
    server.shutdown()
    thread.join()
    
    0 讨论(0)
  • 2020-12-01 05:37

    I should start by saying that "I probably wouldn't do this myself, but I have in the past". The serve_forever (from SocketServer.py) method looks like this:

    def serve_forever(self):
        """Handle one request at a time until doomsday."""
        while 1:
            self.handle_request()
    

    You could replace (in subclass) while 1 with while self.should_be_running, and modify that value from a different thread. Something like:

    def stop_serving_forever(self):
        """Stop handling requests"""
        self.should_be_running = 0
        # Make a fake request to the server, to really force it to stop.
        # Otherwise it will just stop on the next request.
        # (Exercise for the reader.)
        self.make_a_fake_request_to_myself()
    

    Edit: I dug up the actual code I used at the time:

    class StoppableRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
    
        stopped = False
        allow_reuse_address = True
    
        def __init__(self, *args, **kw):
            SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, *args, **kw)
            self.register_function(lambda: 'OK', 'ping')
    
        def serve_forever(self):
            while not self.stopped:
                self.handle_request()
    
        def force_stop(self):
            self.server_close()
            self.stopped = True
            self.create_dummy_request()
    
        def create_dummy_request(self):
            server = xmlrpclib.Server('http://%s:%s' % self.server_address)
            server.ping()
    
    0 讨论(0)
  • 2020-12-01 05:38

    I tried all above possible solution and ended up with having a "sometime" issue - somehow it did not really do it - so I ended up making a dirty solution that worked all the time for me:

    If all above fails, then brute force kill your thread using something like this:

    import subprocess
    cmdkill = "kill $(ps aux|grep '<name of your thread> true'|grep -v 'grep'|awk '{print $2}') 2> /dev/null"
    subprocess.Popen(cmdkill, stdout=subprocess.PIPE, shell=True)
    
    0 讨论(0)
  • 2020-12-01 05:47

    This is a simplified version of Helgi's answer for python 3.7:

    import threading
    import time
    from http.server import ThreadingHTTPServer, SimpleHTTPRequestHandler
    
    
    class MyServer(threading.Thread):
        def run(self):
            self.server = ThreadingHTTPServer(('localhost', 8000), SimpleHTTPRequestHandler)
            self.server.serve_forever()
        def stop(self):
            self.server.shutdown()
    
    
    if __name__ == '__main__':
        s = MyServer()
        s.start()
        print('thread alive:', s.is_alive())  # True
        time.sleep(2)
        s.stop()
        print('thread alive:', s.is_alive())  # False
    
    0 讨论(0)
  • 2020-12-01 05:49

    Another way to do it, based on http://docs.python.org/2/library/basehttpserver.html#more-examples, is: instead of serve_forever(), keep serving as long as a condition is met, with the server checking the condition before and after each request. For example:

    import CGIHTTPServer
    import BaseHTTPServer
    
    KEEP_RUNNING = True
    
    def keep_running():
        return KEEP_RUNNING
    
    class Handler(CGIHTTPServer.CGIHTTPRequestHandler):
        cgi_directories = ["/cgi-bin"]
    
    httpd = BaseHTTPServer.HTTPServer(("", 8000), Handler)
    
    while keep_running():
        httpd.handle_request()
    
    0 讨论(0)
  • 2020-12-01 05:53

    In my python 2.6 installation, I can call it on the underlying TCPServer - it still there inside your HTTPServer:

    TCPServer.shutdown
    
    
    >>> import BaseHTTPServer
    >>> h=BaseHTTPServer.HTTPServer(('',5555), BaseHTTPServer.BaseHTTPRequestHandler)
    >>> h.shutdown
    <bound method HTTPServer.shutdown of <BaseHTTPServer.HTTPServer instance at 0x0100D800>>
    >>> 
    
    0 讨论(0)
提交回复
热议问题