[英]Connections outlive SocketServer.TCPServer?
How can I make a TCP server properly close sockets? 如何使TCP服务器正确关闭套接字?
I wrote a simple TCP server to echo some information back to client. 我编写了一个简单的TCP服务器,将某些信息回显给客户端。 Now I would like to use it on localhost:8088 and stop it using
killall
and restart at any time as I'm working on the code. 现在,我想在localhost:8088上使用它,并使用
killall
停止它,并在我处理代码时随时重新启动。
However, I'm having trouble making it close all sockets and "free" the address, so when I quickly make a few tests, fix something in the code and then stop (Ctrl+C) and start the server again, I get socket.error: [Errno 98] Address already in use
. 但是,我无法使其关闭所有套接字并“释放”地址,因此,当我快速进行一些测试时,修复代码中的某些内容,然后停止(Ctrl + C)并再次启动服务器,我得到了
socket.error: [Errno 98] Address already in use
。
When I sudo netstat -ntap
, I can still see few 127.0.0.1:8088
sockets in TIME_WAIT state. 当我
sudo netstat -ntap
,我仍然可以看到几个127.0.0.1:8088
套接字处于TIME_WAIT状态。 So I have to wait until they "die out". 所以我必须等到他们“消亡”。
My test case: 我的测试用例:
#!/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()
What am I doing wrong? 我究竟做错了什么? Shouldn't
self.request.close()
be enough? self.request.close()
是否足够?
I'm trying this on Debian with Python 2.7.3, although I need to support Squeeze with Python 2.6 as well. 我正在使用Python 2.7.3在Debian上进行尝试,尽管我也需要在Python 2.6中支持Squeeze。
The TCP stack puts the port into timed-wait for awhile (something like 30 seconds to multiple minutes depending on your system). TCP堆栈将端口置于定时等待一段时间(大约30秒到几分钟,具体取决于您的系统)。 You can change that behavior with the SO_REUSEADDR socket option.
您可以使用SO_REUSEADDR套接字选项更改该行为。 The trick is that the option must be set before the port is bound.
诀窍是必须在绑定端口之前设置该选项。
If you have the raw socket, you can: 如果您有原始套接字,则可以:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
SocketServer lets you set the option globally with the allow_reuse_address attribute: SocketServer允许您使用allow_reuse_address属性全局设置选项:
SocketServer.TCPServer.allow_reuse_address = True
Or you can do it when you create the server: 或者,您可以在创建服务器时执行以下操作:
def main():
server = SocketServer.TCPServer((HOST, PORT), MyEchoHandler, False)
server.allow_reuse_address = True
server.server_bind()
server.serve_forever()
Or even override the bind method: 甚至重写bind方法:
class MyTCPServer(SocketServer.TCPServer):
def server_bind(self):
self.allow_reuse_address = True
super(MyTCPServer, self).server_bind()
Here are 3 solutions that worked for me on my Windows machine. 以下是在Windows计算机上对我有用的3种解决方案。
(1) set globally (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) Set locally (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) Inherit (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.