time-wait状态产生的原因
推荐2篇学习TCP的博客文章:
TCP的那些事儿
TCP协议疑难杂症全景解析
可以看相关实际然后和这篇博客结合起来,希望对一起学习的小伙伴有帮助。
TCP的状态机
其实网络上的传输是没有连接,包括TCP也是一样的。而TCP所谓的“连接”,其实只不过是在通讯的双方维护一个“连接状态”,让它看上去好像有连接一样。所以,TCP的状态变换是非常重要的。下面是TCP状态机图片:
1.time_wait状态:
由上面的TCP状态图可知,首先调用close()发起主动关闭的一方,在发送最后一个ACK之后会进入time-wait状态,也就是说该发送方会保持2MSL事件之后才会回到初始状态。MSL值是数据包在网络中的最大生存事件。产生这种结果使得这个TCP连接在2MSL连接等待期间,定义的这个连接的四元数组(local_ip, local_port, remote_ip,remote_port)不能被使用。
2.time_wait状态原因:
1.实现TCP全双工连接的可靠释放
由TCP转换图可知,假设发起主动关闭的一方(client)最后发送的ACK在网络中丢失,由于TCP协议的重传机制,执行被动关闭的一方(server)将会重发其FIN,在该FIN到达client之前,client必须维护这条连接状态,也就是说这条TCP所连接的对应资源(client方的local_ip,local_port)不能被立即释放或重新分配,直到另一方重发的FIN到达 之后,client重发ACK之后,经过2MSL时间周期没有再收到另一方的FIN之后该TCP连接才能恢复到初始的closed状态。如果主动关闭的一方不去维护这个time_wait状态,那么当被关闭一方重发的FIN到达时,主动关闭一方的TCP传输层会用RST包响应对方,这会被对方认为是有错误发生,然而这些事实上只是正常的关闭连接的过程,并非异常。
为了使旧的数据包在网络中因过期而消失
我们先假设TCP协议中不存在TIME_WAIT状态的额限制,再假设当前有一条TCP连接:(local_ip, local_port, remote_ip,remote_port),因为某些原因,我们先关闭,接着很快以相同的四元组建立一条新的连接。本文前面介绍过,TCP连接由四元组唯一标识,因此,在我们假设的情况中,TCP协议栈是无法区分连接的不同的,在它看来,这根本就是同一条连接,中间先释放再连接的过程它也是“感知”不到的。这样就可能发生这样的情况:前一条TCP连接由local peer发送的数据到达remote peer后,会被该remot peer的TCP传输层当做当前TCP连接的正常数据接收并向上传递至应用层(而事实上,在我们假设的场景下,这些旧数据到达remote peer前,旧连接已断开且一条由相同四元组构成的新TCP连接已建立,因此,这些旧数据是不应该被向上传递至应用层的),从而引起数据错乱进而导致各种无法预知的诡异现象。作为一种可靠的传输协议,TCP必须在协议层面考虑并避免这种情况的发生,这正是TIME_WAIT状态存在的第2个原因。
time_wait状态如何避免
首先服务器可以设置SO_REUSEADDR套接字选项来通知内核,如果端口忙,但TCP连接位于TIME_WAIT状态时可以重用端口。在一个非常有用的场景就是,如果你的服务器程序停止后想立即重启,而新的套接字依旧希望使用同一端口,此时SO_REUSEADDR选项就可以避免TIME_WAIT状态。