设置TIME_WAIT的原因
相信大家对tcp的三次握手和四次挥手的过程已经非常熟悉了,但是对于四次挥手来说,有个问题一直困扰着我,那就是为什么在server端发送LAST_ACK之后,还要等待TIME_WAIT时间呢?原因有二:
一、保证TCP协议的全双工连接能够可靠关闭
二、保证这次连接的重复数据段从网络中消失
先说第一点,如果Client直接CLOSED了,那么由于IP协议的不可靠性或者是其它网络原因,导致Server没有收到Client最后回复的ACK。那么Server就会在超时之后继续发送FIN,此时由于Client已经CLOSED了,就找不到与重发的FIN对应的连接,最后Server就会收到RST而不是ACK,Server就会以为是连接错误把问题报告给高层。这样的情况虽然不会造成数据丢失,但是却导致TCP协议不符合可靠连接的要求。所以,Client不是直接进入CLOSED,而是要保持TIME_WAIT,当再次收到FIN的时候,能够保证对方收到ACK,最后正确的关闭连接。
再说第二点,如果Client直接CLOSED,然后又再向Server发起一个新连接,我们不能保证这个新连接与刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。一般来说不会发生什么问题,但是还是有特殊情况出现:假设新连接和已经关闭的老连接端口号是一样的,如果前一次连接的某些数据仍然滞留在网络中,这些延迟数据在建立新连接之后才到达Server,由于新连接和老连接的端口号是一样的,又因为TCP协议判断不同连接的依据是socket pair,于是,TCP协议就认为那个延迟的数据是属于新连接的,这样就和真正的新连接的数据包发生混淆了。所以TCP连接还要在TIME_WAIT状态等待2倍MSL,这样可以保证本次连接的所有数据都从网络中消失。
TIME_WAIT为什么是2MSL
要了解这个问题,我们要先了解另外一个问题,那就是什么是MSL
什么是MSL
MSL是报文最大生存时间(Maximum Segment Lifetime)的缩写,指任何报文在网络上存在的最长时间。超过这个时间,报文将被丢弃。这个参数在TCP协议中尤为重要,用于确保数据传输的可靠性和网络资源的有效利用。
TIME_WAIT为什么是2MSL
搞懂什么是MSL后,TIME_WAIT为什么设置成2MSL也就比较简单了:
- 确保ACK报文到达:在TCP四次挥手过程中,主动关闭方发送完最后一个ACK报文后进入TIME_WAIT状态。如果这个ACK报文丢失,被动关闭方会超时重传FIN报文。等待2MSL的时间可以确保主动关闭方有足够的时间收到并重传这个ACK报文,从而确保连接的可靠关闭。
- 防止旧报文干扰新连接:在TCP网络中,可能存在由于网络延迟等原因而延迟到达的报文段。如果新旧连接具有相同的四元组(源IP地址、目标IP地址、源端口、目标端口),旧连接的报文段可能会在新连接建立后被误收,导致数据混淆。等待2MSL的时间可以确保旧连接的所有报文段在网络中都已消失或被丢弃,从而避免它们对新连接的干扰。
- 确保数据传输的完整性:在TIME_WAIT状态期间,主动关闭方可以确保所有已发送的数据包都被接收方确认,从而确保数据传输的完整性。这是TCP协议可靠性的一个重要体现。等待2MSL的时间可以确保所有可能的重传和确认过程都已经完成。
- 双向清理:TCP连接是全双工的,即数据可以在两个方向上同时传输。等待2MSL的时间可以确保两个方向上的数据包都被正确处理,从而实现连接的双向清理。这个时间长度考虑了报文段在网络中的往返时间,确保所有报文段都已经从网络中消失。
- 避免端口立即被使用:在TIME_WAIT状态期间,定义这个连接的套接口(即IP地址和端口号)不能再被使用。这是为了防止在端口被复用的时候收到迷路包从而出现收包错误。等待2MSL的时间可以确保这个端口在重新使用前是安全的,不会受到旧连接报文段的影响。
综上所述,TIME_WAIT状态持续2MSL是基于对网络延迟、报文生存时间、TCP协议可靠性以及端口复用的综合考虑而得出的。这个时间长度能够确保TCP连接的可靠终止和避免潜在的数据混淆问题。如果TIME_WAIT状态持续的时间过短,可能会增加新旧连接报文段冲突的风险;如果过长,则会浪费系统资源。因此,2MSL是一个相对合理的折衷选择。
造成TIME_WAIT过多的原因
如果有一天,你查看服务器的时候发现有很多TIME_WAIT状态的tcp连接,那么可能是哪里有问题呢?大概率是服务器上存在了大量的短链接,因为如果连接时间过短,那TIME_WAIT状态在整个四次挥手的过程中占用的时间的比例就会相对较大,此时便会更容易出现TIME_WAIT状态的tcp连接。