作为运维出身的我,原本应该对于time_wait很理解才对.   今天看到知乎上一个涉及到tcp建立连接和time_wait的时候,又有些迷糊了.  另外我负责的电商数据抓取也会有大量的time_wait的情况.  在我接触的场景下,web服务器和主动发起请求的爬虫服务都会造成大量的time_wait情况.

文章写的不是很严谨,欢迎来喷,另外该文后续有更新的,请到原文地址查看更新. 

http://xiaorui.cc/2015/12/29/%E5%86%8D%E6%AC%A1%E7%90%86%E8%A7%A3tcp%E5%85%B3%E9%97%AD%E8%BF%9E%E6%8E%A5%E5%87%BA%E7%8E%B0time_wait%E7%9A%84%E6%83%85%E5%86%B5/




Client向Server发送FIN包,表示Client主动要关闭连接,然后进入FIN_WAIT_1状态,等待Server返回ACK包。

此后Client不能再向Server发送数据,但能读取数据。
Server收到FIN包后向Client发送ACK包,然后进入CLOSE_WAIT状态,此后Server不能再读取数据,但可以继续向Client发送数据。

Client收到Server返回的ACK包后进入FIN_WAIT_2状态,等待Server发送FIN包。
Server完成数据的发送后,将FIN包发送给Client,然后进入LAST_ACK状态,等待Client返回ACK包,此后Server既不能读取数据,也不能发送数据。
Client收到FIN包后向Server发送ACK包,然后进入TIME_WAIT状态,接着等待足够长的时间(2MSL)以确保Server接收到ACK包,最后回到CLOSED状态,释放网络资源。

Server收到Client返回的ACK包后便回到CLOSED状态,释放网络资源。

文字流程图:

TCP连接的建立到关闭,需要经历以下状态迁移(假定Client发起连接,并主动关闭连接):

Client
CLOSED -> SYN_SENT -> ESTABLISHED -> FIN_WAIT_1 -> FIN_WAIT_2 -> TIME_WAIT -> CLOSED

Server
CLODES -> LISTEN -> SYN_RECEIVED -> ESTABLISHED -> CLOSE_WAIT -> LAST_ACK -> CLOSED


但是为什么有时候会有大量TIME_WAIT状态出现?

这种情况比较常见,一些爬虫服务器或者WEB服务器(这种情况一般是没有做内核参数优化)上经常会遇到这个问题,这个问题是怎么产生的呢?


从 上面的示意图可以看得出来,TIME_WAIT是主动关闭连接的一方保持的状态,在发完最后一个ack状态后,发起者的状态会调整为TIME_WAIT。 对于爬虫服务器来说他本身就是“客户端”,在完成一个爬取任务之后,他就 会发起主动关闭连接,从而进入TIME_WAIT的状态,然后在保持这个状态2MSL(max segment lifetime)时间之后,彻底关闭回收资源。2MSL一般是大于30s,小于4分钟. 最小也要30s,再大就没啥意义了.  为什么要这么做?明明就已经主动关闭连接了为啥还要保持资源一段时间呢?这个是TCP/IP的设计者规定 的,主要出于以下两个方面的考虑:


1. 收到ack,但是迷路回包的情况: 防止上一次连接中的包,迷路后重新出现,影响干扰新连接(经过2MSL,上一次连接中所有的重复包都会消失)


2. ack丢失的情况: 在主动关闭方发送的最后一个 ack(fin) ,有可能丢失。这时候对方(被动方)会重新发fin, 如果这时主动方处于 CLOSED 状态 ,就会响应 rst 而不是 ack。所以主动方要处于 TIME_WAIT 状态,而不能是 CLOSED 。另外这么设计TIME_WAIT 会定时的回收资源,并不会占用很大资源的,除非短时间内接受大量请求或者受到攻击。

如果接收到rst,也就是tcp连接重置,服务端应用有报错。 


reset报文发送场景:
RST的标志位,这个标识为在如下几种情况下会被设置,以下是我了解的情况,可能还有更多的场景,没有验证

当尝试和未开放的服务器端口建立tcp连接时,服务器tcp将会直接向客户端发送reset报文
双方之前已经正常建立了通信通道,也可能进行过了交互,当某一方在交互的过程中发生了异常,如崩溃等,异常的一方会向对端发送reset报文,通知对方将连接关闭
当收到TCP报文,但是发现该报文不是已建立的TCP连接列表可处理的,则其直接向对端发送reset报文
ack报文丢失,并且超出一定的重传次数或时间后,会主动向对端发送reset报文释放该TCP连接

另外我们做大量api请求时会遇到下面的问题. Broken pipe和Connection reset by peer  .   这其实也是reset的报错一种.


对于tcp的理解抄袭并参考了不少google出来的文章, 勿喷 ! 



对Python及运维开发感兴趣的朋友可以加QQ群 : 478476595 !!!
{ 2000人qq大群内有各厂大牛,常组织线上分享及沙龙,对高性能及分布式场景感兴趣同学欢迎加入该QQ群 }

另外如果大家觉得文章对你有些作用!   帮忙点击广告. 一来能刺激我写博客的欲望,二来好维护云主机的费用.
如果想赏钱,可以用微信扫描下面的二维码. 另外再次标注博客原地址  xiaorui.cc  ……   感谢!
暂无相关产品