Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何重新启动BaseHTTPServer实例?_Python - Fatal编程技术网

Python 如何重新启动BaseHTTPServer实例?

Python 如何重新启动BaseHTTPServer实例?,python,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.star

这就是我所拥有的:

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服务器似乎没有正常停止。我还需要做什么来阻止它

编辑:

我称之为restarttp:

def commandHTTPReload(self, parts, byuser, overriderank):
    self.client.factory.restartHTTP()
    self.client.sendServerMessage("HTTP server reloaded.")

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

您只需要让操作系统知道您确实希望在关闭端口后立即重新使用它。通常它会在关闭状态下保持一段时间,以防出现任何额外的数据包。您可以使用SO_REUSEADDR执行此操作:

mysocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
..打开mysocket后。使用HTTPServer执行此操作的一个好位置可以是重写的
server\u 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等等。

你只需要让操作系统知道你真的想在关闭端口后立即重用它。通常它会在关闭状态下保持一段时间,以防出现任何额外的数据包。您可以使用SO_REUSEADDR执行此操作:

mysocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
..打开mysocket后。使用HTTPServer执行此操作的一个好位置可以是重写的
server\u 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等。

要优雅地停止HTTPServer并关闭套接字,您应该使用:

# Start server
httpd = HTTPServer(...)
httpd.serve_forever()
# Stop server
httpd.shutdown()
httpd.server_close()

要正常停止HTTPServer并关闭套接字,应使用:

# Start server
httpd = HTTPServer(...)
httpd.serve_forever()
# Stop server
httpd.shutdown()
httpd.server_close()

然后把代码放在你调用restarttp的地方。你确定你最初是在端口80上启动服务器的吗?是的,我确定它和以前是同一个端口。然后把代码放在你调用restarttp的地方。你确定你最初是在端口80上启动服务器的吗?是的,我确定它和以前是同一个端口。这不起作用。此外,我认为这不是唯一的问题,因为我还尝试在服务器关闭后延迟5秒启动服务器,但仍然没有成功;通常,一个套接字将在
等待时间内挂起,阻止其他套接字绑定到同一端口,时间为最大段生存期的两倍(因此,4分钟)。在添加了SO_REUSEADDR之后,您是否仍然会遇到完全相同的错误?是的,这似乎没有什么区别。我用一些附加信息编辑了答案,这应该会有所帮助。查看BaseHTTPServer中HTTPServer的实现,socket.SO_REUSEADDR在默认情况下已经使用,所以这个答案是不正确的。这不起作用。此外,我认为这不是唯一的问题,因为我还尝试在服务器关闭后延迟5秒启动服务器,但仍然没有成功;通常,一个套接字将在
等待时间内挂起,阻止其他套接字绑定到同一端口,时间为最大段生存期的两倍(因此,4分钟)。添加了SO_REUSEADDR后,您是否仍然会遇到完全相同的错误?是的,这似乎没有什么区别。我用一些附加信息编辑了答案,这应该会有所帮助。查看BaseHTTPServer中HTTPServer的实现,socket.SO_REUSEADDR在默认情况下已经使用,因此此答案不正确。