19

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

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。

4

4 回答 4

26

感谢其他答案,我想通了。allow_reuse_address应该在类上,而不是在实例上:

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

不过,我仍然不确定为什么关闭套接字并没有为服务器的下一次运行释放它。

于 2013-03-07T17:54:04.293 回答
13

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

尽管可以进行变异TCPServer.allow_reuse_addr(如其他答案中所建议的那样),但我认为您自己的TCPServerwhere子类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()and .server_activate()before 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()
于 2017-02-09T22:17:29.780 回答
3

这是因为 TCP TIME_WAIT

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

但是,如果我尝试停止并再次启动服务器以测试任何修改,我会收到一个随机的“socket.error: [Errno 98] Address already in use”错误。仅当客户端已连接到服务器时才会发生这种情况。

通过 netstat 和 ps 检查,我发现虽然它自己的进程不再运行,但套接字仍在侦听状态为“TIME_WAIT”的端口。基本上,操作系统会等待一段时间以确保此连接在途中没有剩余的数据包。

于 2013-03-07T04:25:31.817 回答
0

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

于 2013-03-07T05:11:19.027 回答