Linux 错误:在将套接字与地址绑定时地址已在使用中,但端口号被`netstat` 显示为空闲

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5106674/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 00:23:23  来源:igfitidea点击:

Error: Address already in use while binding socket with address but the port number is shown free by `netstat`

clinuxsockets

提问by Durin

I tried to bind my socket(server socket) at port number 8000. It worked and did the job for me. At the end of the code I close the socket as well. The very next instant I run my code again and it shows me that the address is already in use. I have printed the meaning of error values strerror(errno);to see if my code working properly at each point. To check if the port is free I checked it using netstatbut it shows that port number 8000is free. It has happened with me a lot of times. Every time I then wait for a few more secs and then it starts working again. I am using c language. So what is he reason for this behavior by my OS.

我试图在端口号绑定我的套接字(服务器套接字)8000。它为我工作并完成了工作。在代码的末尾,我也关闭了套接字。下一刻我再次运行我的代码,它告诉我地址​​已经在使用中。我已经打印了错误值的含义,strerror(errno);以查看我的代码是否在每个点都能正常工作。要检查端口是否空闲,我使用netstat它进行了检查,但它显示端口号8000是空闲的。它在我身上发生了很多次。每次我再等几秒钟,然后它又开始工作。我用的是c语言。那么我的操作系统出现这种行为的原因是什么。

After a few more secs I run the code and then it works.

几秒钟后,我运行代码,然后它就可以工作了。

anirudh@anirudh-Aspire-5920:~/Desktop/testing$ sudo ./a.out 
Socket Creation: Success
File open: Success
Socket Bind: Address already in use
Socket Listen: Address already in use
^C
anirudh@anirudh-Aspire-5920:~/Desktop/testing$ sudo netstat -lntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1348/lighttpd   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      984/sshd        
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN      1131/cupsd      
tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN      1211/mysqld     
tcp6       0      0 :::22                   :::*                    LISTEN      984/sshd        
tcp6       0      0 ::1:631                 :::*                    LISTEN      1131/cupsd      
anirudh@anirudh-Aspire-5920:~/Desktop/testing$ sudo ./a.out 
Socket Creation: Success
File open: Success
Socket Bind: Address already in use
Socket Listen: Address already in use
^C
anirudh@anirudh-Aspire-5920:~/Desktop/testing$ 

采纳答案by icfantv

I've run into that same issue as well. It's because you're closing your connection to the socket, but not the socket itself. The socket can enter a TIME_WAIT state (to ensure all data has been transmitted, TCP guarantees delivery if possible) and take up to 4 minutes to release.

我也遇到了同样的问题。这是因为您正在关闭与套接字的连接,而不是套接字本身。套接字可以进入 TIME_WAIT 状态(以确保所有数据都已传输,TCP 尽可能保证交付)并需要最多 4 分钟释放

or, for a REALLY detailed/technical explanation, check this link

或者,要获得非常详细的/技术说明,请查看此链接

It's certainly annoying, but it's not a bug. See the comment from @Vereb on this answer below on the use of SO_REUSEADDR.

这当然很烦人,但这不是错误。请参阅@Vereb 对此答案的评论,关于SO_REUSEADDR.

回答by hipe

Try netstat like this: netstat -ntp, without the -l. It will show tcp connection in TIME_WAITstate.

像这样尝试 netstat:netstat -ntp,没有-l. 它将显示 tcp 连接 TIME_WAIT状态。

回答by programmer

Just type

只需输入

unlink [SOCKET NAME]

in the terminal, then the error should no longer exist.

在终端中,那么错误应该不再存在。

回答by Clock ZHONG

Even icfantv's answer to this question is already perfect, I still have more findings in my test.

甚至icfantv对这个问题的回答已经很完美了,我的测试中还有更多的发现。

As a server socket in listening status, if it only in listening status, and even it accepts request and getting data from the client side, but without any data sending action. We still could restart the server at once after it's stopped. But if any data sending action happens in the server side to the client, the same service(same port) restart will have this error: (Address already in use).

作为一个处于监听状态的服务端socket,如果它只是处于监听状态,它甚至接受来自客户端的请求和获取数据,但没有任何数据发送动作。我们仍然可以在停止后立即重新启动服务器。但是如果在服务器端发生任何向客户端发送数据的动作,同一个服务(同一个端口)重启就会出现这个错误:(地址已经被使用)。

I think this is caused by the TCP/IP design principles. When the server send the data back to client, it must ensure the data sending succeed, in order to do this, the OS(Linux) need monitor the connection even the server application closed this socket. But I still believe kernel socket designer could improve this issue.

我认为这是由 TCP/IP 设计原则造成的。当服务器将数据发送回客户端时,它必须确保数据发送成功,为此,即使服务器应用程序关闭了此套接字,操作系统(Linux)也需要监视连接。但我仍然相信内核套接字设计者可以改善这个问题。

回答by Supamee

I know its been a while since the question was asked but I was able to find a solution:

我知道这个问题已经有一段时间了,但我找到了解决方案:

int sockfd;
int option = 1;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));

This set the socket able to be reused immediately.

这设置了可以立即重用的套接字。

I apologize if this is "wrong". I'm not very experienced with sockets

如果这是“错误”,我深表歉意。我对套接字不是很有经验

回答by JamesAD-0

the error i received was:

我收到的错误是:

cockpit.socket: Failed to listen on sockets: Address already in use

the fix I discovered is:

我发现的修复是:

  1. I had to disable selinux
  2. in /usr/lib/systemd/system/cockpit service i changed the line :

    #ExecStartPre=/usr/sbin/remotectl certificate --ensure --user=root --group=cockpit-ws --selinux-type=etc_t
    

    to:

    #ExecStartPre=/usr/sbin/remotectl certificate --ensure --user=root --group=cockpit-ws 
    
  1. 我不得不禁用selinux
  2. 在 /usr/lib/systemd/system/cockpit 服务中,我更改了以下行:

    #ExecStartPre=/usr/sbin/remotectl certificate --ensure --user=root --group=cockpit-ws --selinux-type=etc_t
    

    到:

    #ExecStartPre=/usr/sbin/remotectl certificate --ensure --user=root --group=cockpit-ws 
    

so as you can see i took out the argument about selinux then i ran:

正如你所看到的,我拿出了关于 selinux 的论点,然后我跑了:

systemctl daemon-reload
systemctl start cockpit.service

then I browsed to:

然后我浏览到:

I accepted the self-signed certificate and was able to login successfully to cockpit and use it normally.

我接受了自签名证书,并且能够成功登录到驾驶舱并正常使用它。

this is all on a fedora25 machine. the 9090 port had already been added using firewall-cmd

这一切都在 Fedora25 机器上。9090 端口已经添加使用firewall-cmd

回答by Jér?me Pouiller

As already said, your socket probably enter in TIME_WAITstate. This issue is well described by Thomas A. Finehere.

如前所述,您的套接字可能进入TIME_WAIT状态。Thomas A. Fine在这里很好地描述了这个问题。

To summary, socket closing process follow diagram below:

总结一下,socket关闭过程如下图:

Socket closing process

套接字关闭过程

Thomassays:

托马斯说:

Looking at the diagram above, it is clear that TIME_WAITcan be avoided if the remote end initiates the closure. So the server can avoid problems by letting the client close first. The application protocol must be designed so that the client knows when to close. The server can safely close in response to an EOF from the client, however it will also need to set a timeout when it is expecting an EOF in case the client has left the network ungracefully. In many cases simply waiting a few seconds before the server closes will be adequate.

查看上图,很明显,TIME_WAIT如果远程端启动关闭,则可以避免。所以服务器可以通过让客户端先关闭来避免问题。必须设计应用程序协议,以便客户端知道何时关闭。服务器可以安全地关闭以响应来自客户端的 EOF,但是它也需要在期待 EOF 时设置超时,以防客户端不正常地离开网络。在许多情况下,只需在服务器关闭前等待几秒钟就足够了。

Using SO_REUSEADDRis commonly suggested on internet, but Thomasadd:

SO_REUSEADDR互联网上通常建议使用,但Thomas补充说:

Oddly, using SO_REUSEADDRcan actually lead to more difficult "address already in use" errors. SO_REUSADDRpermits you to use a port that is stuck in TIME_WAIT, but you still can not use that port to establish a connection to the last place it connected to. What? Suppose I pick local port 1010, and connect to foobar.com port 300, and then close locally, leaving that port in TIME_WAIT. I can reuse local port 1010 right away to connect to anywhere except for foobar.comport 300.

奇怪的是,使用SO_REUSEADDR实际上会导致更困难的“地址已在使用”错误。SO_REUSADDR允许您使用卡在 中的端口TIME_WAIT,但您仍然无法使用该端口建立与它最后连接到的位置的连接。什么?假设我选择本地端口 1010,并连接到 foobar.com 端口 300,然后在本地关闭,将该端口留在TIME_WAIT. 我可以立即重用本地端口 1010 以连接到foobar.com端口 300以外的任何地方。

回答by dr_begemot

For AF_UNIX you can use call unlink (path); after close() socket in "server" app

对于 AF_UNIX,您可以使用 call unlink (path); 在“服务器”应用程序中的 close() 套接字之后