我知道socketserver有一个方法shutdown()
这会导致服务器关闭,但这仅适用于多线程应用程序,因为关闭需要从与 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()
我知道此代码无效。我只是想向您展示我想完成的事情 - 在用户按下 CtrlC 时关闭服务器并退出应用程序,同时等待传入数据。
最佳答案
您可以在处理程序中本地启动另一个线程,然后从那里调用 shutdown
。
工作演示:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import SimpleHTTPServer
import SocketServer
import time
import thread
class MyHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def do_POST(self):
if self.path.startswith('/kill_server'):
print "Server is going down, run it again manually!"
def kill_me_please(server):
server.shutdown()
thread.start_new_thread(kill_me_please, (httpd,))
self.send_error(500)
class MyTCPServer(SocketServer.TCPServer):
def server_bind(self):
import socket
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind(self.server_address)
server_address = ('', 8000)
httpd = MyTCPServer(server_address, MyHandler)
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass
httpd.server_close()
一些注意事项:
- 要终止服务器,请向
http://localhost:8000/kill_server
发送POST 请求。 - 我创建调用
server.shutdown()
的函数并从另一个线程运行它以解决我们讨论的问题。 - 我使用来自 Binding Socket: “Address already in use” 的建议使套接字立即可供重用(您可以再次运行服务器而不会出现[Errno 98] Address already in use 错误)。使用标准的 TCPServer,您将不得不等待连接超时才能再次运行您的服务器。
关于python - 在单线程 Python 应用程序中关闭 socketserver serve_forever(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10085996/