繁体   English   中英

连接超过SocketServer.TCPServer吗?

[英]Connections outlive SocketServer.TCPServer?

如何使TCP服务器正确关闭套接字?

我编写了一个简单的TCP服务器,将某些信息回显给客户端。 现在,我想在localhost:8088上使用它,并使用killall停止它,并在我处理代码时随时重新启动。

但是,我无法使其关闭所有套接字并“释放”地址,因此,当我快速进行一些测试时,修复代码中的某些内容,然后停止(Ctrl + C)并再次启动服务器,我得到了socket.error: [Errno 98] Address already in use

当我sudo netstat -ntap ,我仍然可以看到几个127.0.0.1:8088套接字处于TIME_WAIT状态。 所以我必须等到他们“消亡”。

我的测试用例:

#!/usr/bin/python
import SocketServer

class MyEchoHandler(SocketServer.BaseRequestHandler):

    def handle(self):
        self.data = self.request.recv(1024).strip()
        # do something smart with the data, but for now, just say hello.
        self.reply = "Content-Type: text/plain\r\n\r\nhello."
        self.request.send(self.reply)
        self.request.close()

def main():
    server = SocketServer.TCPServer((HOST, PORT), MyEchoHandler)
    server.serve_forever()

if __name__ == '__main__':
    HOST, PORT = "localhost", 8088
    main()

我究竟做错了什么? self.request.close()是否足够?

我正在使用Python 2.7.3在Debian上进行尝试,尽管我也需要在Python 2.6中支持Squeeze。

TCP堆栈将端口置于定时等待一段时间(大约30秒到几分钟,具体取决于您的系统)。 您可以使用SO_REUSEADDR套接字选项更改该行为。 诀窍是必须在绑定端口之前设置该选项。

如果您有原始套接字,则可以:

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 

SocketServer允许您使用allow_reuse_address属性全局设置选项:

SocketServer.TCPServer.allow_reuse_address = True

或者,您可以在创建服务器时执行以下操作:

def main():
    server = SocketServer.TCPServer((HOST, PORT), MyEchoHandler, False)
    server.allow_reuse_address = True
    server.server_bind()
    server.serve_forever()

甚至重写bind方法:

class MyTCPServer(SocketServer.TCPServer):

    def server_bind(self):
        self.allow_reuse_address = True
        super(MyTCPServer, self).server_bind()

以下是在Windows计算机上对我有用的3种解决方案。

(1)全局设置

#!/usr/bin/python
import SocketServer
import time

SocketServer.allow_reuse_address = True

class MyEchoHandler(SocketServer.BaseRequestHandler):

    def handle(self):
        self.data = self.request.recv(1024).strip()
        # do something smart with the data, but for now, just say hello.
        self.reply = "Content-Type: text/plain\r\n\r\n" + time.asctime()
        self.request.send(self.reply)
        self.request.close()

def main():
    server = SocketServer.TCPServer((HOST, PORT), MyEchoHandler)
    server.serve_forever()

if __name__ == '__main__':
    HOST, PORT = "localhost", 8088
    main()

(2)本地设置

#!/usr/bin/python
import SocketServer
import time

class MyEchoHandler(SocketServer.BaseRequestHandler):

    def handle(self):
        self.data = self.request.recv(1024).strip()
        # do something smart with the data, but for now, just say hello.
        self.reply = "Content-Type: text/plain\r\n\r\n" + time.asctime()
        self.request.send(self.reply)
        self.request.close()

def main():
    server = SocketServer.TCPServer((HOST, PORT), MyEchoHandler, False)
    server.allow_reuse_address = True
    server.server_bind()
    server.server_activate()
    server.serve_forever()

if __name__ == '__main__':
    HOST, PORT = "localhost", 8088
    main()

(3)继承

#!/usr/bin/python
import SocketServer
import time

class MyEchoHandler(SocketServer.BaseRequestHandler):

    def handle(self):
        self.data = self.request.recv(1024).strip()
        # do something smart with the data, but for now, just say hello.
        self.reply = "Content-Type: text/plain\r\n\r\n" + time.asctime()
        self.request.send(self.reply)
        self.request.close()

class MyTCPServer(SocketServer.TCPServer):

    def server_bind(self):
        self.allow_reuse_address = True
        SocketServer.TCPServer.server_bind(self)

def main():
    server = MyTCPServer((HOST, PORT), MyEchoHandler)
    server.serve_forever()

if __name__ == '__main__':
    HOST, PORT = "localhost", 8088
    main()

您可以调用server.shutdown(),但必须从另一个线程8-(IMO,这是Python的TCPServer中的弱点。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM