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

后端 未结 10 1192
渐次进展
渐次进展 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:55

    I think you can use [serverName].socket.close()

    0 讨论(0)
  • 2020-12-01 05:56

    In python 2.7, calling shutdown() works but only if you are serving via serve_forever, because it uses async select and a polling loop. Running your own loop with handle_request() ironically excludes this functionality because it implies a dumb blocking call.

    From SocketServer.py's BaseServer:

    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:
                # XXX: Consider using another file descriptor or
                # connecting to the socket to wake this up instead of
                # polling. Polling reduces our responsiveness to a
                # shutdown request and wastes cpu at all other times.
                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()
    

    Heres part of my code for doing a blocking shutdown from another thread, using an event to wait for completion:

    class MockWebServerFixture(object):
        def start_webserver(self):
            """
            start the web server on a new thread
            """
            self._webserver_died = threading.Event()
            self._webserver_thread = threading.Thread(
                    target=self._run_webserver_thread)
            self._webserver_thread.start()
    
        def _run_webserver_thread(self):
            self.webserver.serve_forever()
            self._webserver_died.set()
    
        def _kill_webserver(self):
            if not self._webserver_thread:
                return
    
            self.webserver.shutdown()
    
            # wait for thread to die for a bit, then give up raising an exception.
            if not self._webserver_died.wait(5):
                raise ValueError("couldn't kill webserver")
    
    0 讨论(0)
  • 2020-12-01 05:56
    import http.server
    import socketserver
    import socket as sck
    import os
    import threading
    
    
    class myserver:
        def __init__(self, PORT, LOCATION):
            self.thrd = threading.Thread(None, self.run)
            self.Directory = LOCATION
            self.Port = PORT
            hostname = sck.gethostname()
            ip_address = sck.gethostbyname(hostname)
            self.url = 'http://' + ip_address + ':' + str(self.Port)
            Handler = http.server.SimpleHTTPRequestHandler
            self.httpd = socketserver.TCPServer(("", PORT), Handler)
            print('Object created, use the start() method to launch the server')
        def run(self):
            print('listening on: ' + self.url )
            os.chdir(self.Directory)
            print('myserver object started')        
            print('Use the objects stop() method to stop the server')
            self.httpd.serve_forever()
            print('Quit handling')
    
            print('Sever stopped')
            print('Port ' + str(self.Port) + ' should be available again.')
    
    
        def stop(self):
            print('Stopping server')
            self.httpd.shutdown()
            self.httpd.server_close()
            print('Need just one more request before shutting down'
    
    
        def start(self):
            self.thrd.start()
    
    def help():
        helpmsg = '''Create a new server-object by initialising
    NewServer = webserver3.myserver(Port_number, Directory_String)
    Then start it using NewServer.start() function
    Stop it using NewServer.stop()'''
        print(helpmsg)
    

    Not a experience python programmer, just wanting to share my comprehensive solution. Mostly based on snippets here and there. I usually import this script in my console and it allows me to set up multiple servers for different locations using their specific ports, sharing my content with other devices on the network.

    0 讨论(0)
  • 2020-12-01 05:57

    This method I use successfully (Python 3) to stop the server from the web application itself (a web page):

    import http.server
    import os
    import re
    
    class PatientHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
        stop_server = False
        base_directory = "/static/"
        # A file to use as an "server stopped user information" page.
        stop_command = "/control/stop.html"
        def send_head(self):
            self.path = os.path.normpath(self.path)
            if self.path == PatientHTTPRequestHandler.stop_command and self.address_string() == "127.0.0.1":
                # I wanted that only the local machine could stop the server.
                PatientHTTPRequestHandler.stop_server = True
                # Allow the stop page to be displayed.
                return http.server.SimpleHTTPRequestHandler.send_head(self)
            if self.path.startswith(PatientHTTPRequestHandler.base_directory):
                return http.server.SimpleHTTPRequestHandler.send_head(self)
            else:
                return self.send_error(404, "Not allowed", "The path you requested is forbidden.")
    
    if __name__ == "__main__":
        httpd = http.server.HTTPServer(("127.0.0.1", 8080), PatientHTTPRequestHandler)
        # A timeout is needed for server to check periodically for KeyboardInterrupt
        httpd.timeout = 1
        while not PatientHTTPRequestHandler.stop_server:
            httpd.handle_request()
    

    This way, pages served via base address http://localhost:8080/static/ (example http://localhost:8080/static/styles/common.css) will be served by the default handler, an access to http://localhost:8080/control/stop.html from the server's computer will display stop.html then stop the server, any other option will be forbidden.

    0 讨论(0)
提交回复
热议问题