python TCPServer 地址已在使用中,但我关闭服务器并使用 `allow_reuse_address`

问题描述 投票:0回答:5

这是我运行服务器的代码:

class MyRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
    #....

PORT = 8089

httpd = SocketServer.TCPServer(("", PORT), MyRequestHandler)
httpd.allow_reuse_address = True

print "Serving forever at port", PORT
try:
    httpd.serve_forever()
except:
    print "Closing the server."
    httpd.server_close()
    raise

然而这就是发生的事情:

^CClosing the server.
Traceback (most recent call last):
  File "server.py", line 118, in <module>
    self.send_error(400, "Unimplemented GET command: %s" % (self.path,))
  File "/home/claudiu/local/lib/python2.6/SocketServer.py", line 224, in serve_forever
    r, w, e = select.select([self], [], [], poll_interval)
KeyboardInterrupt
(.virtualenv)claudiu@xxx:~/xxx$ python server.py
Traceback (most recent call last):
  File "server.py", line 122, in <module>
    httpd = SocketServer.TCPServer(("", PORT), MyRequestHandler)
  File "/home/claudiu/local/lib/python2.6/SocketServer.py", line 402, in __init__
    self.server_bind()
  File "/home/claudiu/local/lib/python2.6/SocketServer.py", line 413, in server_bind
    self.socket.bind(self.server_address)
  File "<string>", line 1, in bind
socket.error: [Errno 98] Address already in use

为什么?我关闭服务器并将

allow_reuse_address
设置为 True...使用 python 2.6.8。

python tcp port bind
5个回答
32
投票

感谢其他答案,我明白了。

allow_reuse_address
应该在类上,而不是在实例上:

SocketServer.TCPServer.allow_reuse_address = True
httpd = SocketServer.TCPServer(("", PORT), MyRequestHandler)

不过,我仍然不确定为什么关闭套接字并没有将其释放以供下次运行服务器使用。


14
投票

[Err 98] Address already in use
是因为套接字是
.close()
,但它仍在等待足够的时间来确保远程TCP收到其连接终止请求的确认(请参阅TIME_WAIT)。默认情况下,如果有套接字绑定到该端口,则不允许绑定套接字,但您可以使用
allow_reuse_address
(SO_REUSEADDR)

覆盖它

虽然可以改变

TCPServer.allow_reuse_addr
(如这个其他答案中所提议的),但我认为对于你自己的
TCPServer
子类来说更干净,其中
allow_reuse_address
设置为
True

import SocketServer
import SimpleHTTPServer
import time

class MyRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
    def do_GET():
        time.sleep(60)
        self.request.sendall("I'm here!")

class ReuseAddrTCPServer(SocketServer.TCPServer):
    allow_reuse_address = True

PORT = 8089

httpd = ReuseAddrTCPServer(("", PORT), MyRequestHandler)
httpd.daemon_threads = True


print "Serving forever at port", PORT
try:
    httpd.serve_forever()
except:
    print "Closing the server."
    httpd.server_close()
    raise

您可以在实例本身上使用明确设置

allow_reuse_address
(不会弄乱类),但您需要使用
TCPServer(..., bind_and_activate=False)
,否则在您有机会更改
allow_reuse_address
设置之前,套接字将被绑定。那么你需要在
.server_bind()
之前手动调用
.server_activate()
serve_forever()

...
httpd = SocketServer.TCPServer(("", PORT), MyRequestHandler, bind_and_activate=False)
httpd.allow_reuse_address = True
httpd.daemon_threads = True
...
httpd.server_bind()
httpd.server_activate()
httpd.serve_forever()

3
投票

这是因为 TCP TIME_WAIT

有人发现了这个确切的问题。

但是,如果我尝试再次停止并启动服务器来测试任何修改,我会收到一个随机的“socket.error: [Errno 98] Address” 已在使用”错误。仅当客户已经 连接到服务器。

用netstat和ps检查,我发现虽然处理它 self 不再运行,套接字仍在侦听端口 状态为“TIME_WAIT”。基本上操作系统会等待一段时间来制作 确保此连接途中没有剩余数据包。


0
投票

这是因为你必须在绑定套接字之前设置SO_REUSEADDRESS。当您一步创建和绑定套接字然后设置它时,已经太晚了。


0
投票
地址已被使用 SocketServer.TCPServer(("", PORT), MyRequestHandler) 时发生错误,所以你无法捕获下面的内容。

© www.soinside.com 2019 - 2024. All rights reserved.