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过多,在操作系统上调整并没有完美的解决方案,反而可能出现各种数据和连接问题。如果确实影响服务运行,可以从服务程序方面想办法解决,比如:
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.com或 https://tlnet.top/contact 发信给我,谢谢!