2013-03-06 22 views
9

这里是我的代码来运行服务器:蟒蛇TCPSERVER地址我关闭服务器,我用`allow_reuse_address`

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)[email protected]:~/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。

回答

13

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

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

我仍然不知道为什么关闭套接字没有释放它的服务器在下次运行,虽然。

3

这是因为TCP TIME_WAIT

Somebody discovered this exact problem.

However, if I try to stop and start the server again to test any modifications, I get a random “socket.error: [Errno 98] Address already in use” error. This happens only if a client has already connected to the server.

Checking with netstat and ps, I found that although the process it self is no longer running, the socket is still listening on the port with status “TIME_WAIT”. Basically the OS waits for a while to make sure this connection has no remaining packets on the way.

+0

不是一个伟大的引用。 *端口*在TIME_WAIT状态下仍然存在*。没有插座,也没有听。 – EJP 2013-03-07 05:12:17

+0

我明白了,但我想知道为什么我的解决方案(在关闭时设置'allow_reuse_address'并关闭套接字)没有修复它。 – Claudiu 2013-03-07 15:21:58

0

这是因为你必须设置SO_REUSEADDRESS 绑定套接字之前。由于您只需一步创建和绑定套接字,然后进行设置,现在已经太晚了。

+0

因此'allow_reuse_address'基本上对默认的'TCPServer'实现没有任何作用?也不应该在程序结束时关闭套接字来防止这个错误? – Claudiu 2013-03-07 15:21:11

3

[Err 98] Address already in use是由于插座是.close()但它仍然在等待足够的时间来传递,以确保远程TCP接收到它的连接终止请求的确认(见TIME_WAIT)。默认情况下,你不能将套接字绑定,如果有一个套接字绑定到端口,但是你可以重写与allow_reuse_address(SO_REUSEADDR)

虽然是可能的变异TCPServer.allow_reuse_addr(如this other answer提出的),我认为是更干净你自己的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设置。然后,你需要serve_forever()之前手动调用.server_bind().server_activate()

... 
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()