sam*_*d0n 18 python sockets socketserver
我知道socketserver有一个方法shutdown()导致服务器关闭但这只适用于多线程应用程序,因为需要从运行serve_forever()的线程以外的线程调用shutdown.
我的应用程序一次只处理一个请求所以我不使用单独的线程来处理请求,我无法调用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()
Run Code Online (Sandbox Code Playgroud)
我知道这段代码不起作用.我只想向您展示我想要完成的事情 - 当用户按下Ctrl-C时关闭服务器并在等待传入数据时退出应用程序.
dmi*_*nov 16
你可以在你的处理程序中本地启动另一个线程,然后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()
Run Code Online (Sandbox Code Playgroud)
几点说明:
http://localhost:8000/kill_server.server.shutdown()从另一个线程调用并运行它来解决我们讨论的问题.SocketServer库使用一些奇怪的方式来处理继承的属性(由于使用了旧样式类,因此进行了猜测)。如果创建服务器并列出其受保护的属性,则会看到:
In [4]: server = SocketServer.TCPServer(('127.0.0.1',8000),Handler)
In [5]: server._
server._BaseServer__is_shut_down
server.__init__
server._BaseServer__shutdown_request
server.__module__
server.__doc__
server._handle_request_nonblock
Run Code Online (Sandbox Code Playgroud)
如果只是在请求处理程序中添加以下内容:
self.server._BaseServer__shutdown_request = True
Run Code Online (Sandbox Code Playgroud)
服务器将关闭。这样做与调用相同server.shutdown(),只是不等待(并死锁主线程)直到关机。
您shutdown实际上应该按照源代码中的指示在其他线程中调用:
def shutdown(self):
"""Stops the serve_forever loop.
Blocks until the loop has finished. This must be called while
serve_forever() is running in another thread, or it will
deadlock.
"""
self.__shutdown_request = True
self.__is_shut_down.wait()
Run Code Online (Sandbox Code Playgroud)
如果您没有在 TCP 处理程序中捕获KeyboardInterrupt(或者重新引发它),它应该向下渗透到根调用,在本例中为调用server_forever()。
不过,我还没有测试过这一点。代码如下所示:
import socketserver # Python2: SocketServer
class TCPServerV4(socketserver.TCPServer):
address_family = socket.AF_INET
allow_reuse_address = True
class TCPHandler(socketserver.BaseRequestHandler):
def handle(self):
data = self.request.recv(4096)
server = TCPServerV4((host, port), TCPHandler)
try:
server.serve_forever()
except KeyboardInterrupt:
server.shutdown()
Run Code Online (Sandbox Code Playgroud)