如何重新启动BaseHTTPServer实例?

时间:2012-05-22 15:58:53

标签: python

这就是我所拥有的:

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.")

我知道命令正在执行,因为我收到它应该发送的消息。

2 个答案:

答案 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()