服务器端“TIME_WAIT”如何工作?

我知道在这方面有不lessSE的问题,我相信在阅读这个问题之前,我会先阅读其中的很多内容。

“服务器端TIME_WAIT ”是指在服务器端启动close()的服务器端套接字对的状态。

我经常看到这些与我相矛盾的言论:

  1. 服务器端的TIME_WAIT是无害的
  2. 你应该devise你的networking应用程序让客户端启动close(),因此让客户端承担TIME_WAIT

我发现这个矛盾的原因是因为客户端上的TIME_WAIT可能是一个问题 – 客户端可以运行可用的端口,所以实质上上面build议将TIME_WAIT的负担移到客户端,从服务器端来看,这不是问题。

客户端的TIME_WAIT当然只是有限数量的用例的一个问题。 大多数客户端 – 服务器解决scheme将涉及一台服务器和许多客户端,客户端通常不会处理足够高的连接数量,这是一个问题,即使他们这样做,也有一些build议“合理”而不是SO_LINGER的0超时,或干预tcp_tw sysctls)作战客户端TIME_WAIT避免太多创build太多的连接。 但是这并不总是可行的,例如对于类的应用程序,例如:

  • 监控系统
  • 负载发生器
  • 代理

另一方面,我甚至不明白服务器端的TIME_WAIT是如何有用的。 TIME_WAIT的原因就在那里,是因为它阻止了将过时的TCP片段注入到不再属于它们的stream中。 对于客户端的TIME_WAIT ,只需简单地创build一个连接,就可以创build一个与该连接可能具有的相同ip:port对的连接(被使用的对被TIME_WAITlocking)。 但是对于服务器端来说,这是不能被阻止的,因为本地地址将具有接受端口,并且总是相同的,并且服务器不能(AFAIK,我只有经validation据)拒绝连接,传入的对等体将创build已经存在于套接字表中的相同的地址对。

我写了一个程序,显示服务器端TIME-WAIT被忽略。 而且,因为testing是在127.0.0.1上完成的,所以内核必须有一个特殊的位,甚至可以告诉它它是服务器端还是客户端(否则元组将会是相同的)。

来源: http : //pastebin.com/5PWjkjEf ,在Fedora 22上testing,默认networkingconfiguration。

 $ gcc -o rtest rtest.c -lpthread $ ./rtest 44400 s # will do server-side close Will initiate server close ... iterates ~20 times successfully ^C $ ss -a|grep 44400 tcp TIME-WAIT 0 0 127.0.0.1:44400 127.0.0.1:44401 $ ./rtest 44500 c # will do client-side close Will initiate client close ... runs once and then connecting... connect: Cannot assign requested address 

因此,对于服务器端的TIME_WAIT ,完全相同端口对上的连接可以立即成功地重新build立,而对于客户端TIME-WAIT ,在第二次迭代中, connect()正确地失败

总而言之,这个问题有两个方面:

  • 服务器端的TIME_WAIT是否真的没有做任何事情,只是因为RFC要求它?
  • 是build议客户端启动close()的原因,因为服务器TIME_WAIT是无用的吗?

在TCP方面,服务器端在这里意味着套接字处于LISTEN状态的主机。

RFC1122允许处于TIME-WAIT状态的套接字接受具有某些条件的新连接

  When a connection is closed actively, it MUST linger in TIME-WAIT state for a time 2xMSL (Maximum Segment Lifetime). However, it MAY accept a new SYN from the remote TCP to reopen the connection directly from TIME-WAIT state, if it: 

有关条件的详细信息,请参阅RFC1122 。 我期望也必须在套接字上匹配被动OPEN(处于LISTEN状态的套接字)。

主动OPEN(客户端连接调用)没有这样的exception,并且必须在套接字处于TIME-WAIT时发出错误,按照RFC793 。

我推测客户端的build议(以TCP的forms表示主机执行主动OPEN即连接)与您的build议大致相同,在一般情况下,它将TIME-WAIT套接字分布在更多的主机上,sockets。 在通常情况下,客户端不会发送可重用服务器上的TIME-WAIT套接字的SYN。 我同意应用这样的build议仍然取决于用例。

这可能是TIME-WAIT实际做的最清楚的例子,更重要的是它为什么重要。 这也解释了为什么要避免Linux机器上的一些“专家”技巧来“减less”TIME-WAIT。

tcp会话由tupple(sourceIP,sourcePort,destIP,destPort)标识。 因此,TIME_WAIT可以在每个TCP连接上工作。

关于方面,在某些情况下,从客户端closures可以减less服务器上的TIME_WAIT套接字,从而稍微减less内存。 在套接字空间耗尽的情况下(由于短暂的端口耗尽)(例如贪婪的客户端与多个连接到同一服务器的客户端),这个问题应该在任何一方解决。

你永远不能确定一个不可靠的协议,你已经收到来自你的对端设备的最后一条消息,因此假设你的对端突然挂断了电话是危险的。 TCP协议的主要缺点是只能同时打开65000个左右的端口。 但是克服这个问题的方法是转移到一个服务器场,这个服务器场的负载比较好,而不是快速回收端口号。 在客户端,如果它是一个基本的工作站,则不太可能会耗尽端口。