Python:绑定套接字:“地址已经在使用”

我有一个关于TCP / IPnetworking上的客户端套接字的问题。 假设我使用

try: comSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) comSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) except socket.error, msg: sys.stderr.write("[ERROR] %s\n" % msg[1]) sys.exit(1) try: comSocket.bind(('', 5555)) comSocket.connect() except socket.error, msg: sys.stderr.write("[ERROR] %s\n" % msg[1]) sys.exit(2) 

创build的套接字将绑定到端口5555.问题是,在结束连接后

 comSocket.shutdown(1) comSocket.close() 

使用wireshark,我看到双方的FIN,ACK和ACKclosures的套接字,我不能再次使用该端口。 我得到以下错误:

 [ERROR] Address already in use 

我想知道怎样才能立即清除端口,以便下次我仍然可以使用同一个端口。

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

setsockopt似乎不能解决问题谢谢!

在绑定套接字之前尝试使用SO_REUSEADDR套接字选项。

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

编辑:我看到你仍然有这个麻烦。 有一个SO_REUSEADDR不起作用的情况。 如果尝试绑定套接字并重新连接到相同的目标(启用了SO_REUSEADDR ),则TIME_WAIT仍然有效。 但是,它将允许您连接到不同的主机:端口。

想到几个解决scheme。 您可以继续重试,直到重新获得连接。 或者,如果客户端启动closures套接字(而不是服务器),那么它应该神奇地工作。

这是我testing完整的代码,绝对不会给我一个“地址已被使用”的错误。 您可以将其保存在一个文件中,然后从要提供的HTML文件的基本目录中运行该文件。 另外,您可以在启动服务器之前以编程方式更改目录

 import socket import SimpleHTTPServer import SocketServer # import os # uncomment if you want to change directories within the program PORT = 8000 # Absolutely essential! This ensures that socket resuse is setup BEFORE # it is bound. Will avoid the TIME_WAIT issue class MyTCPServer(SocketServer.TCPServer): def server_bind(self): self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.socket.bind(self.server_address) Handler = SimpleHTTPServer.SimpleHTTPRequestHandler httpd = MyTCPServer(("", PORT), Handler) # os.chdir("/My/Webpages/Live/here.html") httpd.serve_forever() # httpd.shutdown() # If you want to programmatically shut off the server 

实际上,SO_REUSEADDR标志可能会导致更大的后果:SO_REUSADDR允许您使用TIME_WAIT卡住的端口,但仍不能使用该端口build立到最后连接的地方的连接。 什么? 假设我select本地端口1010,并连接到foobar.com端口300,然后closures本地,在TIME_WAIT留下该端口。 我可以立即重用本地端口1010连接到foobar.com端口300以外的任何地方。

但是,通过确保远程端启动closures(closures事件),您可以完全避免TIME_WAIT状态。 所以服务器可以通过让客户先closures来避免问题。 应用程序协议的devise必须使客户端知道何时closures。 服务器可以安全地closures来响应来自客户端的EOF,但是当客户端不正常地离开networking时,它也将需要设置超时以预期EOF。 在许多情况下,在服务器closures之前等待几秒钟就足够了。

我也build议你学习更多关于networking和networking编程。 你现在至less应该如何使用TCP协议。 该协议是相当微不足道的,因此,可以为您节省大量的时间在未来。

使用netstat命令可以很容易地看到哪些程序((程序名,pid)元组)被绑定到哪个端口以及什么是套接字当前状态:TIME_WAIT,CLOSING,FIN_WAIT等等。

一个非常好的linuxnetworkingconfiguration的解释可以发现https://serverfault.com/questions/212093/how-to-reduce-number-of-sockets-in-time-wait

绑定前需要设置allow_reuse_address。 而不是SimpleHTTPServer运行这个片段:

 Handler = SimpleHTTPServer.SimpleHTTPRequestHandler httpd = SocketServer.TCPServer(("", PORT), Handler, bind_and_activate=False) httpd.allow_reuse_address = True httpd.server_bind() httpd.server_activate() httpd.serve_forever() 

这可以防止服务器在我们有机会设置标志之前进行绑定。

如果您使用TCPServerSimpleHTTPServer面临问题,请覆盖SocketServer.TCPServer.allow_reuse_address (python 2.7.x)或socketserver.TCPServer.allow_reuse_address (python 3.x)属性

 class MyServer(SocketServer.TCPServer): allow_reuse_address = True server = MyServer((HOST, PORT), MyHandler) server.serve_forever() 

socket.socket()应该在socket.bind()之前运行,并使用REUSEADDR

正如Felipe Cruze提到的,你必须在绑定之前设置SO_REUSEADDR。 我在另一个网站上find了解决scheme – 在其他网站上的解决scheme,转载如下

问题是必须在地址绑定到套接字之前设置SO_REUSEADDR套接字选项。 这可以通过inheritanceThreadingTCPServer并覆盖server_bind方法来完成,如下所示:

导入SocketServer,套接字

类MyThreadingTCPServer(SocketServer.ThreadingTCPServer):
     def server_bind(self):
         self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
         self.socket.bind(self.server_address)

对我来说,更好的解决办法是以下几点。 由于closures连接的动作是由服务器完成的,因此setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)不起作用,TIME_WAIT避免在同一个端口上发生新连接,并出现错误:

 [Errno 10048]: Address already in use. Only one usage of each socket address (protocol/IP address/port) is normally permitted 

我终于使用该解决scheme让操作系统select端口本身,如果先例仍在TIME_WAIT中,则使用另一个端口。

我replace了:

 self._socket.bind((guest, port)) 

有:

 self._socket.bind((guest, 0)) 

正如在tcp地址的python套接字文档中指出的那样:

如果提供,在连接之前,source_address必须是套接字要绑定的2元组(主机,端口)。 如果主机或端口分别为“0”或0,则将使用操作系统默认行为。

我知道你已经接受了一个答案,但我相信这个问题与在客户端套接字上调用bind()有关。 这可能是好的,但bind()和shutdown()似乎并不能很好地发挥作用。 另外,SO_REUSEADDR通常与侦听套接字一起使用。 即在服务器端。

你应该传递和ip /端口连接()。 喜欢这个:

 comSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) comSocket.connect(('', 5555)) 

不要调用bind(),不要设置SO_REUSEADDR。

另一个解决scheme当然是在开发环境中,例如使用它的杀死进程

 def serve(): server = HTTPServer(('', PORT_NUMBER), BaseHTTPRequestHandler) print 'Started httpserver on port ' , PORT_NUMBER server.serve_forever() try: serve() except Exception, e: print "probably port is used. killing processes using given port %d, %s"%(PORT_NUMBER,e) os.system("xterm -e 'sudo fuser -kuv %d/tcp'" % PORT_NUMBER) serve() raise e 

我认为最好的方法是通过inputterminalfuser -k [PORT NUMBER]/tcp ,例如fuser -k 5001/tcp来终止该端口上的进程。

我发现只是在while循环中使用这个修复错误

 if KeyboardInterrupt == 1 : sys.exit(1);