三次握手、四次挥手和TIME_WAIT机制
三次握手过程中seq和ack的值:
一个TCP连接的建立是通过三次握手来实现的
1. (A) –> [SYN] –> (B)
假如服务器B和客户机A通讯. 当A要和B通信时,A首先向B发一个SYN (Synchronize) 标记的包,告诉B请求建立连接.
注意: 一个 SYN包就是仅SYN标记设为1的TCP包(参见TCP包头Resources). 认识到这点很重要,只有当B受到A发来的SYN包,才可建立连接,除此之外别无他法。
2. (A) <– [SYN/ACK] <–(B)
接着,B收到后会发一个对SYN包的确认包(SYN/ACK)回去,表示对第一个SYN包的确认,并继续握手操作.
注意: SYN/ACK包是仅SYN 和 ACK 标记为1的包.
3. (A) –> [ACK] –> (B)
A收到SYN/ACK 包,A发一个确认包(ACK),通知B连接已建立。至此,三次握手完成,一个TCP连接完成
注意: 需要注意的是当三此握手完成、连接建立以后,TCP连接的每个包都会设置ACK位
握手阶段的ack和seq值变化:
对上表的解释:
1:A向B发起连接请求,以一个随机数初始化A的seq,这里假设为10000,此时ACK=0,ack无意义
2:B收到A的连接请求后,也以一个随机数初始化B的seq,这里假设为20000,
意思是:你的请求我已收到,我这方的数据流就从这个数开始。B的ACK是A的seq加1,即10000+1=10001
3:A收到B的回复后,它的seq是它的上个请求的seq加1,即10000+1=10001,
意思也是:你的回复我收到了,我这方的数据流就从这个数开始。A此时的ACK是B的seq加1,即20000+1=20001
传输过程中seq和ack值
三次握手建立连接之后,就开始传输数据了
取中间一段的传输过程举例
对上表的解释:
23:B接收到A发来的seq=40000,ack=70000,size=1518的数据包
24:于是B向A也发一个数据包,告诉A,你的上个包我收到了。此时B的seq就是它收到的数据包A的ack,B的ack是它收到的数据包的seq加上该数据包的大小(不包括:
以太网协议头=14字节,IP头=20字节,TCP头=20字节),以证实B发过来的数据全收到了。
25:A在收到B发过来的ack为41460的数据包时,一看到41460,正好是它的上个数据包的seq加上包的大小,就明白,上次发送的数据包已安全到达。
于是它再发一个数据包给B。此时A正在发送的数据包的seq就等于它收到的数据包的ack填充,A的ack 就等于它收到的数据包的seq(70000)加上包的size(54)填充,
即ack=70000+54-54(全是头长,没数据项)。
为什么要减去54?
链路层使用的是Ethernet II 格式,这个格式有14字节MAC帧首部+4字节MAC帧尾部,还有TCP数据报和IP数据报的首部各20个字节):
应用数据=size-14-20-20=size-54。(假设IP首部和TCP首部都没有可选选项)
为什么不减去MAC帧尾部的4字节呢?
因为在物理层上网卡要先去掉前导同步码和帧开始定界符,然后对帧进行CRC检验,如果帧校验和错,就丢弃此帧。如果校验和正确,就判断帧的目 的硬件地址是否符合自己的接收条件(目的地址是自己的物理硬件地址、广播地址、可接收的多播硬件地址等),如果符合,就将帧交“设备驱动程序”做进一步处 理。这时我们的抓包软件才能抓到数据,因此,抓包软件抓到的是去掉前导同步码、帧开始分界符、FCS之外的数据,
四次挥手过程中seq和ack值
终止字符(FIN): 值为1表示要发送的数据报已经发送完毕,需要释放传送连接。
1. (A) –> [FIN/ACK] –> (B)
客户端A没有要发送给服务端B的数据了,想要关闭链接,则发送一个FIN=1,ACK=1的包,告诉B可以关闭连接了,我没有什么数据要给你了。
此时A的状态由ESTAB-LISHED变为FIN-WAIT1状态
2. (A) <– [ACK] <– (B)
然后B会发送ACK=1的包给A,告诉A我知道你没有什么想给我的了,但是我还有数据要处理完,你先等下。此时B的状态由ESTAB-LISHED变为CLOSE-WAIT
3. (A) <– [FIN/ACK] <– (B)
过了一会,服务端处理完数据发送给客户端[FIN/ACK],表明已经处理完数据,最后一次确认是否要准备关闭B->A的通信连接
4. (A) –> [ACK] –> (B)
然后A回应一个ACK,表示确认。B收到这个ACK后,就会CLOSE。但是A不会直接CLOSE,还会进入一个等待时间状态TIME_WAIT,持续2倍的MSL(Maximum Segment Lifetime,报文段在网络上能存活的最大时间,4分钟)。过了这个状态,才会CLOSE。
A为什么要等待一段时间,也就是TIMW-WAIT的作用?原因有二:
(1)保证TCP的全双工连接能够可靠关闭
假如A发送的最后一次ACK丢包了,没有被B收到,那B超时之后,会再次发送一个FIN包,然后这个包被处于TIME_WAIT状态的A收到,A会再次发送一个ACK包,并重新开始计时,一直循环这个过程,直到A在TIME_WAIT的整个过程中都没有收到B发过来的FIN包,这说明B已经收到了A的ACK包并CLOSE了,因此A这时候才可以安心CLOSE。
如果A没有TIME_WAIT状态而是直接close,那么当ACK丢包之后,B会再次发送一个FIN包,但是这个包不会被A回应,因此B最终会收到RST(异常的关闭连接标志),误以为是连接错误,不符合可靠连接的要求。因此需要等待ACK报文到达
(2)保证这次连接的重复数据段从网络中消失
如果A直接close了,然后向B发起了一个新的TCP连接,可能两个连接的端口号相同。一般不会有什么问题,但是如果旧的连接有一些数据堵塞了,没有达到B呢,新的握手连接就已经到B了,那么这时候,由于区分不同TCP连接是依据套接字,因此B会将这批迟到的数据认为是新的连接的数据,导致数据混乱(源IP地址和目的IP地址以及源端口号和目的端口号的组合称为套接字,新旧连接的套接字很有可能相同)
TIME_WAIT的作用(对应上面两点)
1 需要服务端可靠地终止连接,如果处于time_wait客户端发给服务端的ack报文丢失,则服务端会再发一次fin,此时客户端不应该关闭。
2 保证迟来的tcp报文有时间被丢弃,因为2msl里超时抵达的报文都会被丢弃。
注意:TIME_WAIT是主动关闭连接的一方保持的状态
总结
确认号:
在握手和结束时确认号应该是对方序列号加1,传输数据时则是对方序列号加上对方携带应用层数据的长度,如果对方携带应用层数据长度为0,则ack与对方序列号相同,不要+1,比如25的ack与24的seq相同。也可以这样理解,因为24没有发送数据,所以A期待B下次发送过来的第一个字节的序号不变,因此25的ack与23的ack相同。
序列号:
在握手和结束时序列号应该是上次序列号+1,传输数据时则是上次的序列号加上上次应用层数据发送长度,如果数据长度为0,则seq与上次一样,不要+1,比如26的seq和24的seq相同。
以上部分转载自https://blog.csdn.net/happyrocking/article/details/78198776