Python:绑定套接字:"地址已在使用中"

Tu *_*ang 66 python sockets port tcp

我有一个关于TCP/IP网络上的客户端套接字的问题.让我说我用

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)
Run Code Online (Sandbox Code Playgroud)

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

comSocket.shutdown(1)
comSocket.close()
Run Code Online (Sandbox Code Playgroud)

使用wireshark,我看到两侧的FIN,ACK和ACK关闭了套接字,我无法再次使用该端口.我收到以下错误:

[ERROR] Address already in use
Run Code Online (Sandbox Code Playgroud)

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

comSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Run Code Online (Sandbox Code Playgroud)

setsockopt似乎无法解决问题谢谢!

Bry*_*yan 107

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

comSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
Run Code Online (Sandbox Code Playgroud)

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

我想到了几个解决方案.您可以继续重试,直到您可以再次获得连接.或者,如果客户端启动套接字(而不是服务器)的关闭,那么它应该神奇地工作.

  • 你在`bind`之前调用过`setsockopt`吗?是第一个使用`SO_REUSEADDR`创建的套接字,还是只是失败的套接字?等待套接字必须设置为"SO_REUSEADDR"才能生效 (5认同)
  • @jcoffland我同意他不应该使用`bind()`,但是SO_REUSEADDR适用于所有套接字,不仅包括TCP服务器套接字,还包括TCP客户端套接字和UDP套接字。不要在这里发布错误信息。 (2认同)

小智 25

这是我测试过的完整代码,绝对不会给我一个"已经在使用的地址"错误.您可以将其保存在文件中,并从要提供的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
Run Code Online (Sandbox Code Playgroud)


Rus*_*m K 12

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

但是,您可以通过确保远程端启动闭包(close事件)来完全避免TIME_WAIT状态.因此,服务器可以通过让客户端先关闭来避免问题.必须设计应用程序协议,以便客户端知道何时关闭.服务器可以安全地关闭以响应来自客户端的EOF,但是如果客户端不正常地离开网络,它还需要在期望EOF时设置超时.在许多情况下,只需在服务器关闭前等待几秒即可.

我还建议您了解有关网络和网络编程的更多信息.你现在至少应该如何使用tcp协议.该协议非常简单,很小,因此可以为您节省大量时间.

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

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

  • 你应该公平地引用你从[Tom's](http://hea-www.harvard.edu/~fine/Tech/addrinuse.html)网络指南中复制和粘贴的句子.请更正你的答案. (7认同)

And*_*rei 9

如果您遇到问题使用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()
Run Code Online (Sandbox Code Playgroud)


Vuk*_*man 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()
Run Code Online (Sandbox Code Playgroud)

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