这就是我所拥有的:
http.py:
class HTTPServer():
def __init__(self, port):
self.port = port
self.thread = None
self.run = True
def serve(self):
self.thread = threading.Thread(target=self._serve)
self.thread.start()
def _serve(self):
serverAddress = ("", self.port)
self.server = MyBaseHTTPServer(serverAddress,MyRequestHandler)
logging.log(logging.INFO, "HTTP server started on port %s"%self.port)
while self.run:
self.server.handle_request()
def stop(self):
self.run = False
self.server.server_close()
然后在另一个文件中,重新启动它:
def restartHTTP(self):
try:
self.httpserver.stop()
reload(http)
self.httpserver = http.HTTPServer(80)
self.httpserver.serve()
except:
traceback.print_exc()
这给了我一个已经处于使用中的地址错误,所以似乎HTTP服务器没有正常停止。我还需要做些什么来阻止它?
编辑:
我调用restartHTTP:
def commandHTTPReload(self, parts, byuser, overriderank):
self.client.factory.restartHTTP()
self.client.sendServerMessage("HTTP server reloaded.")
我知道命令正在执行,因为我收到它应该发送的消息。
答案 0 :(得分:3)
您只需让操作系统知道您确实希望在关闭后立即重新使用该端口。通常情况下,如果出现任何额外的数据包,它会暂停一段时间。您可以使用SO_REUSEADDR执行此操作:
mysocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
打开mysocket后打开..使用HTTPServer执行此操作的好地方可能是覆盖server_bind
方法:
def server_bind(self):
HTTPServer.server_bind(self)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
编辑:仔细查看了您的代码后,我发现您的线程模型也可能会导致问题。您正在关闭主(?)线程中的套接字,而另一个线程正在等待同一套接字上的连接(在accept()
中)。这种安排没有明确定义的语义,我相信它在不同的操作系统上做了不同的事情。在任何情况下,为了最大限度地减少混淆,你应该避免这种情况(在多线程程序中已经有很多这种情况)。在获得连接并处理其请求之后,您的旧线程实际上不会消失(因为它在此之前不会重新检查self.run
),因此端口可能无法重新绑定直到之后这一点。
这并不是一个简单的解决方案。您可以在线程之间添加通信管道,然后在服务器线程中使用select()
/ poll()
等待其中任何一个上的活动,或者您可以在执行之后超时accept()
个调用短时间,以便更频繁地检查self.run
。或者您可以将主线程连接到侦听套接字本身。但无论你做什么,你都可能接近复杂程度,你应该考虑使用"真正的" httpd或网络框架而不是自己滚动:apache,lighttpd,Tornado,Twisted等。
答案 1 :(得分:1)
要正常停止HTTPServer并关闭套接字,应使用:
# Start server
httpd = HTTPServer(...)
httpd.serve_forever()
# Stop server
httpd.shutdown()
httpd.server_close()