避免 TIME_WAIT

Posted

技术标签:

【中文标题】避免 TIME_WAIT【英文标题】:Avoiding TIME_WAIT 【发布时间】:2009-12-18 22:27:36 【问题描述】:

我试图在客户端中。我连接然后设置 O_NONBLOCK 和 SO_REUSEADDR。我调用 read 直到它返回 0。当 read 返回 0 时,errno 也为 0。我将此解释为服务器关闭连接的标志。但是,如果我调用 close,则套接字将设置为 TIME_WAIT,正如 netstat 所确认的那样。

由于我与同一个主机/端口建立了多个连接,我最终开始看到“正在使用的地址”错误(请参阅http://hea-www.harvard.edu/~fine/Tech/addrinuse.html)。

我应该在 read 返回 0 后调用 close 吗?如果我不这样做,文件描述符会被释放吗?

【问题讨论】:

旁注:读取返回 0 时 errno 值未定义 - errno 仅在失败后定义。 【参考方案1】:

启动关闭连接的一侧是最终处于TIME_WAIT 状态的一侧。 read() 返回 0 应该表示服务器首先关闭了套接字,所以是的 - 这应该意味着 TIME_WAIT 最终在服务器端,客户端通过 LAST_ACK

归根结底,您无法避免TIME_WAIT 状态。即使您成功地将其从客户端移动到服务器端,您仍然无法重新使用该 (server host, server port, client host, client port) 元组,直到 TIME_WAIT 结束(无论它在哪一侧)。

由于该元组的三个部分在您的场景中是固定的(server hostserver portclient host),因此您实际上只有以下选项:

尝试使更多客户端端口可用。默认情况下,某些操作系统仅将一小部分可用端口用于“临时端口”(在这方面我不确定 OSX)。如果是这种情况,请查看是否可以通过操作系统中的配置调整来更改范围,或者让应用程序使用bind()/connect() 在循环中寻找工作端口,直到连接正常。

通过在客户端上使用多个 IP 地址来扩展可用的 client host 值的数量。不过,您必须将应用程序 bind() 专门用于这些 IP 地址之一。

通过在服务器上使用多个端口和/或 IP 地址来扩展可用的 server host/server port 值的数量。客户端需要选择一个连接(循环、随机等)。

如果可行,这可能是最好的选择:重构您的协议,以便完成的连接不会关闭,而是进入“空闲”状态,以便以后可以重新使用,而不是打开一个新的连接(如 HTTP 保持活动)。

【讨论】:

抱歉对一个老问题发表评论,但这个答案的第一段不应该是“发起关闭连接的一方是最终处于 TIME_WAIT 状态的一方”?我似乎记得在某本书中读过,而且,这似乎暗示了hea-www.harvard.edu/~fine/Tech/addrinuse.html【参考方案2】:

稍后在同一页面上,他们提到了 SO_REUSEADDR。这就是你需要的。 您肯定希望在读取文件描述符返回零时关闭它。

【讨论】:

对不起。我忘了补充说我确实设置了 SO_REUSEADDR。在文章中看到,当您连接到同一端口/主机时,它不会阻止使用中的地址错误。【参考方案3】:

在客户端设置 SO_REUSEADDR 对服务器端没有帮助,除非它也设置了 SO_REUSEADDR

【讨论】:

以上是关于避免 TIME_WAIT的主要内容,如果未能解决你的问题,请参考以下文章

正确使用@Async,避免踩坑

避免插入失败以避免虚假的自动增量

如何避免两次编写 SQL Server 查询以避免重复?

MYSQL的UPDATE子查询,UPDATE时避免使用子查询

DDoS攻击是啥?应该如何避免?

Delphi 中要避免的组件