2011-06-17 90 views
52

我有一个关于TCP/IP网络上的客户端套接字的问题。比方说,我用Python:绑定套接字:“地址已在使用”

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) 

创建的套接字将被绑定到端口5555的问题是,结束连接

comSocket.shutdown(1) 
comSocket.close() 

使用Wireshark的后,我看到FIN,ACK和ACK关闭套接字从双方我都不能再使用这个端口。我收到以下错误:

[ERROR] Address already in use 

我想知道我该如何清除端口,以便下次我仍然可以使用相同的端口。

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

setsockopt的似乎并不能够解决问题 谢谢!

+0

为什么客户端需要特定的端口? – 2011-06-17 00:17:29

+1

因为我必须将其放入生产服务器,并在该服务器中,所有传出连接都被阻止。我需要为套接字指定一个特定的端口,以便他们可以在防火墙上设置一条规则,允许连接通过。 – 2011-06-17 00:46:31

+0

我建议你复制并粘贴实际的代码。你上面写的有一个明显的错误,会阻止你看到你声称已经看到的行为。这让读者不知道你有什么疏忽告诉我们可能会导致你的问题。 – 2011-06-17 01:01:06

回答

82

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

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

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

一些解决方案浮现在脑海。您可以继续重试,直到您再次获得连接。或者,如果客户端启动关闭套接字(而不是服务器),那么它应该神奇地工作。

+0

Still无法重复使用它。在重新使用相同端口之前,我必须等待的时间是1分30秒:( – 2011-06-17 00:38:37

+4

是否在'bind'之前调用'setsockopt'?是使用'SO_REUSEADDR'创建的第一个套接字,还是仅仅是失败的套接字? 等待的套接字必须有'SO_REUSEADDR'才能正常工作 – lunixbochs 2011-06-17 01:00:58

+0

是的,我确实包含了comSocket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1),但仍然不起作用 – 2011-06-17 01:04:31

2

socket.socket()socket.bind()之前应该运行和使用REUSEADDR如说

2

正如菲利普·科鲁兹所提到的,必须结合之前设置SO_REUSEADDR。我发现在其他网站上的解决方案 - solution on other site, reproduced below

The problem is that the SO_REUSEADDR socket option must be set before the address is bound to the socket. This can be done by subclassing ThreadingTCPServer and overriding the server_bind method as follows:

 
import SocketServer, socket 

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

1

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

你应该通过和ip/port来连接()。像这样:

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

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

2

对我来说更好的解决方案是以下几点。由于关闭连接的倡议是由服务器完成,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 

我终于用解决方案,让OS选择端口本身,如果先例仍在TIME_WAIT中,则使用另一个端口。

我代替:

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

有:

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

正如有人指出的TCP地址python socket documentation

If supplied, source_address must be a 2-tuple (host, port) for the socket to bind to as its source address before connecting. If host or port are ‘’ or 0 respectively the OS default behavior will be used.

21

下面是完整的代码,我经过测试,绝对不会给我一个“地址已被使用”的错误。您可以将它保存在一个文件中,然后从要提供的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 
+0

即使在httpd.shutdown()之后,您仍然想调用httpd.server_close()来完全释放所有资源。 – Androbin 2018-01-05 23:18:05

+0

另外,考虑使用atexit模块,以防意外存在。 – Androbin 2018-01-05 23:18:59

10

其实之前,SO_REUSEADDR标志可能会导致更大的后果:SO_REUSADDR允许您使用该卡在TIME_WAIT端口,但仍无法使用端口建立到最后连接的地方的连接。什么?假设我选择本地端口1010,并连接到foobar.com端口300,然后关闭本地,将该端口保留在TIME_WAIT中。我可以立即重新使用本地端口1010连接到foobar.com端口300以外的任何地方。

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

我还建议您了解有关网络和网络编程的更多信息。您现在至少应该如何使用tcp协议。该协议是相当平凡和小,因此,可以为您节省大量的时间在未来。

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

对linux网络配置的一个很好的解释可以在https://serverfault.com/questions/212093/how-to-reduce-number-of-sockets-in-time-wait找到。

+0

另外,你应该小心你的代码。如果您的代码仍在开发中,并且发生了一些异常,则连接可能无法正确关闭,尤其是从服务器端关闭。 – 2014-01-07 15:20:04

+5

您应该公平并引用您从[Tom's](http://hea-www.harvard.edu/~fine/Tech/addrinuse.html)网络指南中复制和粘贴的句子。请更正您的答案。 – HelloWorld 2015-09-22 22:46:25

0

另一种解决方案,在课程的开发环境,是杀过程中使用它,例如

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 
6

您需要结合前设置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() 

这可以防止服务器之前,我们有机会来设置标志结合。

+0

继承TCPServer并覆盖属性似乎更容易,请参阅[我的答案](http://stackoverflow.com/questions/6380057/python-binding-socket-address-already-in-use/35363839#35363839)示例 – Andrei 2016-02-12 13:30:15

0

我认为最好的办法就是杀通过输入终端fuser -k [PORT NUMBER]/tcp,例如在该端口上的过程fuser -k 5001/tcp

+0

除非进程已经被杀死,并且它只是将端口打开以便被os清理。 – 2017-06-27 15:40:16

相关问题