【网络编程】地址已经被使用:”Address already in use“

相信不少刚学网络编程的人都会遇上这个问题,在测试自己程序的时候,把原先的服务端程序关了之后,重启一下,发现就出现了”Address already in use“。

下面就来分析一下原因和解决办法:

一、原因

首先来复习一下TIME_WAIT,当连接的一方主动关闭连接,在接收到对端的 FIN 报文之后,主动关闭连接的一方会在 TIME_WAIT 这个状态里停留一段时间,这个时间大约为 2MSL(Windows一般为2min,linux为30s)。如下图所示:

img
这里再来说下存在TIME_WAIT状态的作用:

  • 可靠地终止TCP连接。
  • 允许老的重复分节在网络中消失(保证让迟来的TCP报文段有足够的时间被识别并丢弃)

第一个原因应该大家都知道,简单说下第二个原因

TCP报文段的最大生存时间是MSL,持续2MSL时间的TIME_WAIT状态能够确保网络上两个传输方向上尚未被接收到的、迟到的TCP报文段都已经消失(被中转路由器丢弃)。因此,一个连接的新的化身(也就是和老连接地址和端口的新连接)可以在2MSL事件之后安全的建立,而且绝对不会接收到属于老连接的应用程序数据。当然现在不需要这个特性也能区分新老连接了。

服务端发起的关闭连接操作,就会引起注意一个TCP连接处于TIME_WAIT的现象。也正是这个 TIME_WAIT 的连接,使得服务器重启时,地址和端口不变的话,就会返回“Address already in use ”的错误。

二、解决方法

当然,最容易想到的方法,就是换一个地址或者端口号。不过在现代 Linux 操作系统下,即使使用了相同的地址和端口号,也不会有什么大的问题,原因是现代 Linux 操作系统对此进行了一些优化。

  • 第一种优化是新连接 SYN 告知的初始序列号,一定比 TIME_WAIT 老连接的末序列号大,这样通过序列号就可以区别出新老连接。
  • 第二种优化是开启了 tcp_timestamps,使得新连接的时间戳比老连接的时间戳大,这样通过时间戳也可以区别出新老连接。

在这样的优化之下,一个 TIME_WAIT 的 TCP 连接可以忽略掉旧连接,重新被新的连接所使用。

这就是重用套接字选项,通过给套接字配置可重用属性,告诉操作系统内核,这样的 TCP 连接完全可以复用 TIME_WAIT 状态的连接。代码如下:

int on = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

SO_REUSEADDR 套接字选项,允许启动绑定在一个端口,即使之前存在一个和该端口一样的连接。

前面的例子已经表明,在默认情况下,服务器端历经创建 socket、bind 和 listen 重启时,如果试图绑定到一个现有连接上的端口,bind 操作会失败,但是如果我们在创建 socket 和 bind 之间,使用上面的代码片段设置 SO_REUSEADDR 套接字选项,情况就会不同。

这里需要注意的是,SO_REUSEADDR 是用户态的选项,SO_REUSEADDR 选项用来告诉操作系统内核,如果端口已被占用,但是 TCP 连接状态位于 TIME_WAIT ,可以重用端口。如果端口忙,而 TCP 处于其他状态,重用端口时依旧得到“Address already in use”的错误信息。

三、总结

在所有 TCP 服务器程序中,调用 bind 之前请设置 SO_REUSEADDR 套接字选项。这不会产生危害,相反,它会帮助我们在很快时间内重启服务端程序,而这一点恰恰是很多场景所需要的。

问题一:关于tcp_tw_reuse和SO_REUSEADDR的区别

tcp_tw_reuse是为了缩短time_wait的时间,避免出现大量的time_wait链接而占用系统资源,解决的是accept后的问题;SO_REUSEADDR是为了解决time_wait状态带来的端口占用问题,以及支持同一个port对应多个ip,解决的是bind时的问题。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
根据你提供的引用内容来看,"Address already in use: NET_Bind" 错误通常在网络编程中出现。这个错误通常表示该地址已被其他程序占用。在Windows系统中,可以通过结束javaw.exe进程来解决这个问题,然后重新启动项目即可。 此外,你提到的"hadoop102:10000"可能是你在运行Hadoop时遇到的问题。这个错误可能是由于Hadoop已经在同一个端口上启动了另一个实例。你可以尝试使用不同的端口或者确保没有其他程序在占用该端口来解决这个问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [java.net.BindException: Address already in use: JVM_Bind 异常的解决办法](https://blog.csdn.net/Y1366925106/article/details/51089910)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [jetty:run 启动项目报错:Address already in use: bind](https://blog.csdn.net/qq_38262596/article/details/80624777)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值