我知道socketserver有一个shut down()方法,它会导致服务器关闭,但这只在多线程应用程序中有效,因为关闭需要从不同的线程调用,而不是从serve_forever()正在运行的线程调用。
我的应用程序一次只处理一个请求,因此我不使用单独的线程来处理请求,而且我无法调用shutdown(),因为它会导致死锁(它不在文档中,但直接在socketserver的源代码中声明)。
为了更好地理解,我将在这里粘贴代码的简化版本:
import socketserver
class TCPServerV4(socketserver.TCPServer):
address_family = socket.AF_INET
allow_reuse_address = True
class TCPHandler(socketserver.BaseRequestHandler):
def handle(self):
try:
data = self.request.recv(4096)
except keyboardInterrupt:
server.shutdown()
server = TCPServerV4((host, port), TCPHandler)
server.server_forever()
我知道这段代码不起作用。我只想向您展示我想完成的事情-关闭服务器并退出应用程序,同时等待用户按下Ctrl-C键时输入的数据
您可以在处理程序中本地启动另一个线程,并从中调用
shutdown
。工作演示:
注意事项:
http://localhost:8000/kill_server
请求。server.shutdown()
的函数,并从另一个线程运行它来解决我们讨论的问题。SocketServer库使用一些奇怪的方式来处理继承的属性(由于使用了旧样式的类而猜测)。如果创建服务器并列出其受保护的属性,则会看到:
如果您只是在请求处理程序中添加以下内容:
服务器将关闭。这与调用
server.shutdown()
一样,只是不需要等待(并使主线程死锁)直到它关闭。我相信OP的目的是从请求处理程序关闭服务器,我认为他的代码的
KeyboardInterrupt
方面只是令人困惑的事情。在运行服务器的shell中按
ctrl-c
将成功地在不做任何特殊操作的情况下关闭它。你不能从一个不同的shell按ctrl-c
并期望它工作,我认为这个概念可能是这个混乱的代码的来源。不需要像OP尝试的那样处理handle()
中的KeyboardInterrupt
,或者像另一个建议的那样处理serve_forever()
中的KeyboardInterrupt
。如果你两个都不做,它就会按预期工作。这里唯一的诀窍——而且很棘手——是告诉服务器在不死锁的情况下从处理程序关闭。
正如OP在他的代码中解释和显示的那样,他使用的是单线程服务器,因此建议在“其他线程”中关闭它的用户没有注意到。
我仔细研究了
SocketServer
代码,发现BaseServer
类在处理该模块中可用的线程混合时,实际上通过在serve_forever
中使用threading.Event
循环,使非线程服务器的使用更加困难。因此,我为单线程服务器编写了
serve_forever
的修改版本,这使得从请求处理程序关闭服务器成为可能。如果将字符串
'shutdown'
发送到服务器,服务器将结束其serve_forever
循环。您可以使用netcat进行测试:相关问题 更多 >
编程相关推荐