tcp连接关闭详解和注意事项

来源:互联网 发布:咖啡机品牌 知乎 编辑:程序博客网 时间:2024/06/05 03:33
状态分析
2.1 FIN_WAIT1
这个状态在实际的工作中很少见。主动方调用close函数关闭连接后立刻进入FIN_WAIT1状态,此时只要收到对端确认ACK后马上会进入FIN_WAIT2状态。因为对端确认ACK是TCP协议栈自己控制的,所以很快就会发出。出现场景:主动方等待ACK过程中网络断掉了,导致长时间收不到ACK,主动方就会停留在CLOSE_WAIT1状态上(超时时间:一般默认60s超时)。此时我们可以使用netstat -anpt 命令看到这种状态。
NOTE:这个状态如果超时,将直接进入CLOSED状态。关于超时时间你可能需要了解:tcp_fin_timeout这个配置参数。

2.2 FIN_WAIT2
这个状态比较常见。主动端在等待对端FIN到来过程中,会一你直保持这个状态(超时时间:一般默认是60s)。由于网络中断,或者对端很忙还没来得及发送FIN、或者对端有bug忘记关闭连接等都会导致主动端长时间处于FIN_WAIT2状态。如果主动方发现大量FIN_WAIT2状态时,应该引起相关人员的注意,这可能是网络不稳、对端程序bug的表现。
NOTE:这个状态如果超时,将直接进入CLOSED状态。关于超时时间你可能需要了解:tcp_fin_timeout这个配置参数。

2.3 TIME_WAIT
这个状态最常见。主动方收到对端的FIN后进入TIME_WAIT状态。然后发送最后一个确认ACK到对端。之后等待2个最大的报文存活周期,正常的关闭流程客户端TCP连接都会经过这个状态,最终进入CLOSED状态。所以我们使用netstat -anpt命令发现客户端有很多的TIME_WAIT,一般这是正常的现象。
NOTE:
这个状态的连接还没有真正关闭,所以占用的文件句柄和端口号等资源也没有释放。如果TIME_WAIT状态的连接过多,将会导致文件句柄或者端口号等资源不足。如果你想控制这个状态连接的数量,你可能需要详细了解:tcp_max_tw_buckets tcp_tw_recycle tcp_tw_reuse三个系统配置。
对于有大量短链接服务的服务器来说,服务端主动关闭连接会产生大量的TIME_WAIT,如果不及时回收这些个连接会造成资源严重浪费。不过一个应用层系统都有自己最大并发连接数限制、操作系统也有最大TIME_WAIT连接数限制。所以一般也不会产生大的问题。
* 等待2MSL的原因:
(1)保证残留网络报不会被新连接接收而产生数据错乱。由于自己上一次发送的数据包可能还残留在网络中,等待2MSL时间可以保证所有残留的网络报在自己关闭前都已经超时。
(2)确保自己最后ACK发到对端。因为ACK发送也可能会失败,这是对端会重新发送FIN,如果已经CLOSED了那么对端将收到RST而不是ACK了,这不符合TCP可靠关闭策略。

2.4 CLOSING
双发几乎同时都调用了close接口主动关闭连接,此时都进入了FIN_WAIT1状态。如果在FIN_WAIT1状态期望收到对方的ACK但却收到了对方的FIN,这时候双方都进入CLOSING状态。然后都给对方一个ACK确认,收到了ACK后就会进入CLOSED状态了。
NOTE:这个状态如果超时,将直接进入CLOSED状态。关于这个超时时间的设置我暂时还没有找到?

2.5 CLOSE_WAIT(重点说明下这个状态)
这个状态表明TCP连接等待被关闭。只可能在被动方出现。如果被动方存在大量的CLOSE_WAIT状态需要因为我们的特别注意了。我们要仔细研究确认为什么被动方迟迟不愿关闭连接(或许是我们程序中的bug开启了连接,用完后却忘记关闭)
目前开发过程中遇到如下这个场景导致被动方有很多的CLOSE_WAIT状态:
A是一个应用程序,B是一个tomcat服务器
A开了一个连接Conn,发送请求给B
A接受相应数据后没有调用Conn.close关闭连接,在A端垃圾回收这些Conn对象前,这些连接一直保持着
B端的连接超时后会主动发起关闭连接请求给A,此时A进入了CLOSE_WAIT状态,B进入了FIN_WAIT2状态,由于A迟迟不发送FIN给B,B端触发timeout直接进入了CLOSED状态。
这样一个场景B端由于有超时设置一个为60s,不会存在大量的FIN_WAIT2状态
但是A端就会残留大量的CLOSE_WAIT状态(CLOSE_WAIT状态也有超时,但是太大,默认为43200s,详情见tcp_timeout_close_wait系统配置)。还好A端的java虚拟机的最大对内存配置较小,由于CLOSE_WAIT状态连接同样占用了内存资源,数量很多后就会触发垃圾回收,此时A端的CLOSE_WAIT的连接Conn对象就会被销毁了(同时内存和句柄、端口等资源也被释放了)
很明显这是一个bug导致的问题,如果没有及时回收的话,就会把内存、句柄或者端口等资源给用完,导致程序crash掉。

2.6 LAST_ACK
这个状态只可能在被动端出现。当被动端调用close接口关闭连接后便会进入这个状态,同时发送一个FIN给对端。在接受对端的ACK确认后便会进入CLOSED状态,这个状态一般不易出现,除非网络中断,一般对端会很快给与响应的。

2.7 状态总结
主动端可能出现的状态:FIN_WAIT1、FIN_WAIT2、CLOSING、TIME_WAIT
被动端可能出现的状态:CLOSE_WAIT LAST_ACK
叙述中提到的超时时间在我的另一片文章tcp连接超时那点事中有具体的分析

NOTE:
(1)主动端出现大量的FIN_WAIT1时需要注意网络是否畅通、出现大量的FIN_WAIT2需要仔细检查程序为何迟迟收不到对端的FIN(可能是主动方或者被动方的bug)、出现大量的TIME_WAIT需要注意系统的并发量/socket句柄资源/内存使用/端口号资源等。
(2)被动端出现大量的 CLOSE_WAIT 需要仔细检查为何自己迟迟不愿调用close关闭连接(可能是bug,socket打开用完没有关闭)
原创粉丝点击