避免TIME_WAIT状态

8
我试图在客户端避免TIME_WAIT。我连接并设置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吗?如果不这样做,文件描述符会被释放吗?

旁注:当read返回0时,errno值未定义 - 只有在失败后才定义errno。 - Remember Monica
3个回答

7
发起关闭连接的一方会进入TIME_WAIT状态。如果read()返回0,则应该表示服务器先关闭了套接字,因此是服务器端结束在TIME_WAIT状态中,客户端经过LAST_ACK状态。
归根结底,无法避免TIME_WAIT状态。即使成功将其从客户端移动到服务器端,也无法在TIME_WAIT结束之前重用该元组(server host, server port, client host, client port)(无论它在哪一侧)。
由于您的场景中有三个元组部分是固定的(server host、server port、client host),因此您只有以下选项:
- 尝试提供更多的客户端端口。某些操作系统默认仅使用少量可用端口作为“临时端口”(我不确定OSX在这方面的情况)。如果是这样,请尝试通过操作系统中的配置调整范围,或者使用bind()/connect()在循环中寻找可用端口,直到连接成功。 - 通过在客户端上使用多个IP地址来扩展可用的客户端主机值。但是,应用程序必须绑定到其中一个特定的IP地址。 - 通过在服务器上使用多个端口和/或IP地址来扩展可用的服务器主机/服务器端口值。客户端需要选择一个进行连接(轮询、随机等)。 - 如果可能的话,可能是最好的选择:重构您的协议,使已完成的连接不会关闭,而是进入“空闲”状态,以便稍后可以重用它们,而不是打开新连接(如HTTP keep-alive)。

抱歉评论一下旧问题,但是这个答案的第一段不应该是“发起关闭连接的一方最终处于TIME_WAIT状态吗?我好像记得在某本书中读到过,而且在http://hea-www.harvard.edu/~fine/Tech/addrinuse.html中也可以看到。 - zentrunix

1

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


抱歉,我忘记提到我确实设置了SO_REUSEADDR。请在文章中查看,它无法防止在连接到相同的端口/主机时出现地址已在使用错误。 - richcollins

1

在客户端设置SO_REUSEADDR并不能帮助服务端,除非服务端也设置了SO_REUSEADDR。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接