Python的SocketServer中的TCPServer + BaseRequestHandler在每次handle()调用后会关闭套接字吗?

10 投票
4 回答
9705 浏览
提问于 2025-04-15 18:02

我正在用Python写一个客户端/服务器的应用程序,发现每次客户端发请求时,都需要重新连接服务器。我的服务器是从TCPServer继承来的,而我则是从BaseRequestHandler继承来处理请求的。在处理请求的过程中,我并没有在任何地方调用self.request.close(),但是服务器似乎还是和我的客户端断开了连接。这是怎么回事呢?

4 个回答

6

根据文档,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)
7
  1. 每次处理完请求后,tcpserver都会关闭连接。
  2. 下面的代码在对方关闭连接时不起作用。

    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
    
    1. reuseaddr 这个设置不起作用,因为在绑定之后再设置已经太晚了。
    server.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
9

好的,我看了代码(在我的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。

所以,我的问题的答案是“是的”。

撰写回答