Please enable Javascript to view the contents

TCP三次握手四次挥手备忘

 ·  ☕ 4 分钟

重要

最重要的事:

1.简介

seq: 序号,TCP连接中传送的字节流中的每个字节都按顺序编号。

ack: 确认号,是期望收到对方下一个报文的第一个数据字节的序号。

SYN: 同步SYN,在连接建立时用来同步序号。当SYN=1,ACK=0,表明是连接请求报文,若同意连接,则响应报文中应该使SYN=1,ACK=1

ACK: 确认ACK,仅当ACK=1时,确认号字段才有效。TCP规定,在连接建立后所有报文的传输都必须把ACK置1;

FIN: 终止FIN,用来释放连接。当FIN=1,表明此报文的发送方的数据已经发送完毕,并且要求释放;

三次握手

过程:

x= 随机生成序列号
y= 随机生成序列号

客户端[SYN_SENT ]—-SYN=1,seq=x (请求连接)——————->[ ]服务端
客户端[ ]<—SYN=1,ACK=1,ack=x+1,seq=y(应答客户端SYN,并请求建立连接)–>[SYN_RCVD ]服务端
客户端[ESTABLISHED]–ACK=1,ack=Y+1 (应答服务端SYN)—————>[ESTABLISHED]服务端

三次握手而非两次的原因:

如果客户端发送请求连接-1,由于网络原因超时,客户端重试再次发出请求连接-2,此时正常建立连接并完成通信;
之后网络回复请求连接-1再次送达服务端, 此时服务端响应的应答客户端SYN请求被返回客户端,此时客户端不会再
发出应答服务端端SYN请求,server收不到确认请求,则不会建立连接。

四次挥手

过程:

断开过程由客户端或服务端任一方执行close来触发。TCP连接是全双工的,因此,每个方向都必须要单独进行关闭
x=等于前面已经传送过来的数据的最后一个字节的序号加1
y=自身序列号
z=服务端释放的报文可能携带数据

客户端[FIN_WAIT_1]—-FIN=1,seq=x (client请求释放)———–>[ ]服务端
客户端[FIN_WAIT_1]<—ACK=1,ack=x+1,seq=y (释放确认报文)————–>[CLOSE-WAIT ]服务端
客户端[FIN_WAIT_2]<—FIN=1,ACK=1,ack=y+1,seq=z (server请求释放)————[LAST-ACK ]服务端
客户端[TIME-WAIT ]—-ACK=1,ack=z+1,seq=y+1 (最终释放确认报文)———–>[CLOSE ]服务端
2∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
客户端[CLOSE]

为什么客户端最后还要等待2MSL?

MSL(Maximum Segment Lifetime), 报文段最大生存时间,它是任何报文段被丢弃前在网络内的最长时间。
第一,保证TCP协议的全双工连接能够可靠关闭保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,
站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,
应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,
而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。

第二,保证这次连接的重复数据段从网络中消失 防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。
客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。
这样新的连接中不会出现旧连接的请求报文。

为什么建立连接是三次握手,关闭连接确是四次挥手呢?

建立连接的时候,服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,
所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,
因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。

Reference

两张动图-彻底明白TCP的三次握手与四次挥手

分享

Hex
作者
Hex
CloudNative Developer

目录