如何在BaseHTTPRequestHandler子类中停止BaseHTTPServer.serve_forever()?
我在一个单独的线程中运行我的 HTTPServer
(使用线程模块,但这个模块没有办法停止线程……),我想在主线程关闭时停止处理请求。
Python的文档说 BaseHTTPServer.HTTPServer
是 SocketServer.TCPServer
的一个子类,后者支持一个 shutdown
方法,但在 HTTPServer
中却没有这个方法。
整个 BaseHTTPServer
模块的文档非常少 :(
12 个回答
29
事件循环会在接收到SIGTERM信号、按下Ctrl+C,或者调用shutdown()
时结束。
在调用server_forever()
之后,必须调用server_close()
来关闭监听的套接字。
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等)来停止:
server = StoppableHTTPServer(("127.0.0.1", 8080),
http.server.BaseHTTPRequestHandler)
server.run()
服务器在一个线程中运行:
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()
42
还有一种方法可以实现,参考这个链接:http://docs.python.org/2/library/basehttpserver.html#more-examples。这个方法不是一直运行服务器,而是只在满足某个条件的时候继续提供服务。服务器会在每次处理请求之前和之后检查这个条件。举个例子:
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()
30
我先说一下,“我可能自己不会这样做,但我以前确实做过”。serve_forever(来自SocketServer.py)这个方法是这样的:
def serve_forever(self):
"""Handle one request at a time until doomsday."""
while 1:
self.handle_request()
你可以在子类中把while 1
替换成while self.should_be_running
,然后可以从其他线程修改这个值。大概是这样的:
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()
补充:我找到了当时用的实际代码:
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()