How to stop BaseHTTPServer.serve_forever() in a BaseHTTPRequestHandler subclass?
我在单独的线程中运行
Python文档指出
整个
我首先要说:"我自己可能不会做,但过去我会做。" serve_forever(来自SocketServer.py)方法如下所示:
1 2 3 4 | def serve_forever(self): """Handle one request at a time until doomsday.""" while 1: self.handle_request() |
您可以将
1 2 3 4 5 6 7 | 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() |
编辑:我挖出了我当时使用的实际代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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() |
在我的python 2.6安装中,我可以在基础TCPServer上调用它-它仍然在
1 2 3 4 5 6 7 8 | TCPServer.shutdown >>> import BaseHTTPServer >>> h=BaseHTTPServer.HTTPServer(('',5555), BaseHTTPServer.BaseHTTPRequestHandler) >>> h.shutdown <bound method HTTPServer.shutdown of <BaseHTTPServer.HTTPServer instance at 0x0100D800>> >>> |
基于http://docs.python.org/2/library/basehttpserver.html#more-examples的另一种实现方法是:只要满足条件,就继续提供服务,而不是serve_forever()。服务器在每个请求之前和之后检查条件。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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() |
我认为您可以使用
事件循环在SIGTERM,Ctrl + C或调用
必须在
1 2 3 4 5 6 7 8 9 10 11 | 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() |
可通过用户操作停止简单服务器(SIGTERM,Ctrl + C等):
1 2 3 | server = StoppableHTTPServer(("127.0.0.1", 8080), http.server.BaseHTTPRequestHandler) server.run() |
服务器在线程中运行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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() |
在python 2.7中,仅当您通过serve_forever服务时才调用shutdown()有效,因为它使用了异步选择和轮询循环。具有讽刺意味的是,使用handle_request()运行您自己的循环会排除此功能,因为这意味着一个愚蠢的阻塞调用。
从SocketServer.py的BaseServer中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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() |
这是我的代码的一部分,用于使用事件等待完成来阻止其他线程关闭:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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") |
我成功使用了此方法(Python 3)从Web应用程序本身(网页)停止服务器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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() |
这样,默认处理程序将为通过基地址
我尝试了上述所有可能的解决方案,最终遇到了"有时"问题-某种程度上它并没有真正做到-因此我最终做出了一个肮脏的解决方案,该解决方案一直对我有用:
如果以上所有方法均失败,则使用以下类似方法强行杀死线程:
1 2 3 | 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) |