浅谈tcp状态 time_wait ,close_wait, fin_wait_2


tcp关闭时常遇到的中间状态:time_wait ,close_wait,fin_wait_2

time_wait的产生:本机tcp的time_wait状态,是本地tcp主动关闭了tcp连接后产生的。需要一定时间,系统才会彻底释放tcp资源。

time_wait的作用防止前一个连接上延迟的数据包或者重传的数据包被重新复用该tcp连接的连接错误接收. 另一方面,由于处于time_wait的tcp连接还没有释放,如果最后返回的ack丢失,还可以接收对方重传的fin并ack给对方,使对方快速从last_ack进入closed状态。所以time_wait的存在是有作用的。

解决time_wait过多问题:

1,限制或回收

time_wait 状态保持本身是一种正常情况,只有在确实影响到程序正常运作时,才用限制或回收的方式来解决,这种方式本身也要承担数据丢失的风险。比如:

net.ipv4.tcp_max_tw_buckets=8192 可以限制time_wait在总数. 到上限时(如8192)则不会有新的time_wait产生.

net.ipv4.tcp_tw_recycle=1快速回收time_wait (该参数在内核4.12后已废弃)

要注意: tcp_tw_recycle和tcp_timestamps两个系统变量同时开启产生的问题,tcp_timestamps是默认开启的.开启tcp_tw_recycle后,当time_wait被回收后,同一IP的数据包时间戳比之前(回收前)上传数据包时间戳小时,数据包直接会被丢掉。

2,调整服务程序

服务端time_wait过多,在操作系统上调整并没有完美的解决方案,反而可能出现各种数据和连接问题。如果确实影响服务运行,可以从服务程序方面想办法解决,比如:

  • 服务端不再主动关闭连接,把主动关闭连接转移到客户端。
  • 客户端开启连接重用tcp_tw_reuse;
  • 或者服务程序开启KeepAlive,短链接改长链接等。
  • 这种种方式可以归纳为:设法减少链接数和转移关闭链接端;这些要根据具体的环境来调整。


time_wait经常看到是属于正常情况,但一般 close_wait,fin_wait_2两个状态如果经常看到过多,很大可能属于异常情况了,说明有程序需要调整,因为这两个是过渡状态,正常情况下应该很快被转换为其他状态,比如fin_wait_2应该快速转到下一个状态time_wait,而close_wait应该快速转到下一个状态last_ack.


关闭连接状态转换过程

(图片来自网络)

(图片来自网络)


close_wait的产生:tcp连接中,对方关闭了连接,本地tcp接收对方fin回复ack,后关闭本地连接发送fin给对方,但由于没有发送本地fin,出现close_wait,换句话说,对方连接关闭了,本地连接没有关闭。大多数情况下,这是程序设计可以解决的问题。从状态转换的条件上可以看出close_wait不需要远程发送任何标识,只要本地关闭连接,就可以转到last_ack,所以,close_wait过多,必然是本地没有关闭连接引起的。

解决close_wait过多问题:监测socket,发现不可用时,关闭socket。


fin_wait_2的产生:主动关闭连接,等待对方fin时,对方没有关闭连接,没有发送fin,与上面close_wait的形成对应,对方形成close_wait状态,本地进入fin_wait_2状态,如果对方一直没有关闭连接,本地会一直在fin_wait_2状态直至超时,在linux上,可以通过系统变量net.ipv4.tcp_fin_timeout 设置tcp 连接的fin_wait_2保持的时间(默认60秒),如 net.ipv4.tcp_fin_timeout=30 则fin_wait_2最长会被保持30秒。

解决fin_wait_2过多问题,首先找到远程没有关闭连接的原因,如果是程序问题,远程tcp程序 应该解决close_wait问题。其次可以根据实际情况设置net.ipv4.tcp_fin_timeout.


状态被保持没有转到下一个状态时,表示连接资源没有被释放,对于tcp监听方(一般时服务端)来说,是资源浪费;对于连接发起端(一般是客户端)来说,占用了系统资源,特别是端口资源,过多时导致无法再向外建立新的连接。



有任何问题或建议请Email:donnie4w@gmail.comhttps://tlnet.top/contact  发信给我,谢谢!