0

我有一个假的 HTTP 服务器,在我的测试中用作固定装置。在测试的某个时刻,我想停止服务器,而不管任何仍然打开的连接。这些打开的连接上的客户端应该获得一个 TCP FIN。

我知道通常生产服务器需要解决不同的问题,即quiescing,有时称为优雅关闭。这与我想要的相反。

使用独立进程,通常可以简单地让进程退出,操作系统会处理其余的工作。(强行杀死进程很容易,而强行杀死线程则不然。)但是,我的假服务器运行在测试进程本身的线程中,所以我没有这个选项(我不想外部化它如果有其他方法)。

我在 Python 中使用HTTPServer 类调查了这个问题,但我找不到任何解决方案。

我还在 Go 中对此进行了调查,在那里我能够找到Contexts的概念,这与我需要的很接近,但它的工作方式相反:http 服务器将传播一个 Context 可用于取消例如数据库查找客户端是否断开连接。

编辑:看起来 Go 实际上做了我需要的,并且有一个单独的优雅和非优雅关闭方法,其中非优雅是net/http#Server.Close

server = http.server.HTTPServer(...)
thread = threading.Thread(run=server.serve_forever)
thread.start()

# a client has connected ....

server.shutdown()
# at this point I want to have the server stopped,
# without waiting for the request handling to complete

4

1 回答 1

0

我已经用 Python 实现了 Go 解决方案。当新客户端连接时,我记得客户端套接字,当我想退出时,我关闭所有记住的套接字。

它似乎工作。

import socket
import http.server.HTTPServer

class MyHTTPServer(HTTPServer):
    """Adds a method to the HTTPServer to allow it to exit gracefully"""

    def __init__(self, addr, handler_cls):
        super().__init__(addr, handler_cls)
        self._client_sockets: List[socket.socket] = []

        self.server_killed = False

    def get_request(self) -> Tuple[socket.socket, Any]:
        """Remember the client socket"""
        sock, addr = super().get_request()
        self._client_sockets.append(sock)
        return sock, addr

    def shutdown_request(self, request: socket.socket) -> None:
        """Forget the client socket"""
        self._client_sockets.remove(request)
        print(f"{self._client_sockets=}")
        super().shutdown_request(request)

    def force_disconnect_clients(self) -> None:
        """Shutdown the remembered sockets"""
        for client in self._client_sockets:
            client.shutdown(socket.SHUT_RDWR)

用法

server = MyHTTPServer(server_addr, MyRequestHandler)

# in a new thread
while not server.server_killed:
    self._server.handle_request()

# ... use the server (keep in mind it can have at most one client at a time) ...

# in the main program
server.server_killed = True
server.force_disconnect_clients()
server.server_close()
于 2022-02-10T22:18:54.090 回答