Python的SocketServer中的TCPServer + BaseRequestHandler在每次handle()调用后会关闭套接字吗?
我正在用Python写一个客户端/服务器的应用程序,发现每次客户端发请求时,都需要重新连接服务器。我的服务器是从TCPServer继承来的,而我则是从BaseRequestHandler继承来处理请求的。在处理请求的过程中,我并没有在任何地方调用self.request.close(),但是服务器似乎还是和我的客户端断开了连接。这是怎么回事呢?
4 个回答
根据文档,TCPServer和BaseRequestHandler都不会主动关闭套接字,除非你特别要求它们这样做。它们的默认实现中,handle()
和finish()
这两个方法其实什么都不做。
可能发生的情况有几种:
- 你可能在某个地方关闭了套接字本身,或者关闭了包装它的请求,或者调用了
server_close
。 - 套接字的超时时间可能到了,而你实现了一个超时处理程序,这个处理程序会关闭套接字。
- 客户端可能实际上关闭了套接字。提供一些代码会更有助于找出问题所在。
不过,我的测试结果确认了你的观察。一旦你从服务器的handle
方法返回,无论是通过telnet还是Python的socket
模块连接,你的连接都会显示为被远程主机关闭。在handle
内部用循环处理套接字活动似乎是有效的:
def handle(self):
while 1:
try:
data = self.request.recv(1024)
print self.client_address, "sent", data
except:
pass
简单的Google代码搜索确认了这是处理请求的典型方式:1 2 3 4。老实说,如果我遇到SocketServer
提供的抽象和我的期望之间的脱节,我可能会考虑使用Python的其他网络库。
我用来测试的代码示例:
from SocketServer import BaseRequestHandler, TCPServer
class TestRequestHandler(BaseRequestHandler):
def handle(self):
data = self.request.recv(1024)
print self.client_address, "sent", data
self.request.send(data)
class TestServer(TCPServer):
def __init__(self, server_address, handler_class=TestRequestHandler):
TCPServer.__init__(self, server_address, handler_class)
if __name__ == "__main__":
import socket
address = ('localhost', 7734)
server = TestServer(address)
server.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- 每次处理完请求后,tcpserver都会关闭连接。
下面的代码在对方关闭连接时不起作用。
def handle(self): while 1: try: data = self.request.recv(1024) print self.client_address, "sent", data except: pass
这样写可能会更好:
def handle(self): while(1): try: self.data = self.request.recv(1024) if not self.data: print "%s close" % self.client_address[0] break print "%s wrote:" % self.client_address[0], self.data except: print "except" break
reuseaddr
这个设置不起作用,因为在绑定之后再设置已经太晚了。
server.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
好的,我看了代码(在我的Mac上,SocketServer.py文件位于/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/)。
确实,TCPServer会关闭连接。在BaseServer.handle_request
这个方法里,会调用process_request
,而这个方法又会调用close_request
。在TCPServer类中,close_request
会执行self.request.close()
,而self.request
就是用来处理请求的那个socket。
所以,我的问题的答案是“是的”。