三次握手和四次挥手原理

180 阅读5分钟

三次握手和四次挥手详细原理

使用TCP协议前,需要进行三次握手,结束TCP协议前,需要进行四次挥手。
注:seq:(Sequence Number):本报文段数据的第一个字节的序号
ack:(Acknowledgment Number):确认号——期望收到对方下个报文段的第一个数据字节的序号
SYN(synchronize):请求同步标志——用于建立和释放连接,当SYN=1时,表示建立连接。
ACK(acknowledge):确认标志——仅当 ACK=1时确认号字段才有效。建立 TCP 连接后,所有报文段都必须把 ACK 字段置为 1。
FIN(Finally):结束标志——用于释放连接,当 FIN=1,表明发送方已经发送完毕,要求释放TCP连接。

三次握手

第一次握手:客户端给服务器发送连接请求包SYN=1(seq=x),等待服务器回应.
第二次握手:服务器端收到请求包后,将客户端的请求包SYN=1(seq=x)放入到自己的未连接队列,此时服务器需要发送两个包给客户端:
(1) 向客户端发送确认自己接收到其连接请求的确认包SYN=1(seq=x),向客户端表明已知道了其连接请求。
(2) 向客户端发送连接询问请求包SYN=1(seq=y),询问客户端是否已经准备好建立连接,进行数据通信。
此时服务器进入SYN_RECV状态。
第三次握手:客户端收到服务器的包后,知道服务器同意建立连接;向服务器发送连接建立的确认包ACK=1(ack=y+1),回应服务器的SYN=1(seq=y)告诉服务器,我们之间建立了连接,可以进行数据通信。
ACK=1(ack=y+1)包发送完毕,服务器收到后,此时服务器与客户端进入EStablished状态,开始进行数据传送。

四次挥手

(1)客户端向服务器发送断开连接请求的报文段,seq=m(m为客户端最后一次向服务器发送报文段的最后一个字节序号加1),客户端进入FIN-WAIT-1状态(第一次挥手)
(2)服务器收到断开报文段后,向客户端发送确认报文段,seq=n(n为服务器最后一次向客户端发送报文段的最后一个字节序号加1), ack=m+1, 服务器进入ClOSE-WAIT状态,此时TCP连接处于半开半闭状态,服务器发送数据的话,客户端仍然可以接收到。(第二次挥手)
(3)服务器向客户端发送断开确认报文段,seq=u(u为半开半闭状态下服务器最后一次向客户端发送报文段的最后一个字节序号加1),ack=m+1,服务器进入LAST-ACK状态。(第三次挥手)
(4)客户端收到服务器的断开确认报文段后,向服务器发送确认断开报文,seq=m+1, ack=u+1, 客户端进入TIME-WAIT状态(第四次挥手)
(5)服务器收到客户端的确认断开报文,进入CLOSED状态,断开了TCP连接。
(6)客户端在TIME-WAIT状态等待一段时间(时间为2*MSL(Maximum Segmnet Life)),确认客户端向服务器发送的最后一次断开确认到达(如果没有到达,服务器会重发步骤(3)中的断开确认报文段给客户端,告诉客户端你的最后一次确认断开没有收到)。如果客户端在TIME-WAIT过程中没有再次收到服务器的报文段,就进入CLOSED状态。TCP连接至此断开。

为什么要使用这种机制

为什么要三次握手

握手的过程实际上是在通知对方自己的初始化序号(Initial Sequence Number),简称ISN,也就是上图中的x和y。x和y会被当作之后传输数据的一个依据,以保证TCP报文在传输过程中不会混乱。

解决两个问题:
1、避免连接请求的数据包丢失
假设连接途中,客户端网络不稳定出现丢包,服务端根据seq=x来确定客户端请求到第几个包。然后告诉客户端你从第seq=x个包开始发送给我,之前的不用发送了,我这里有记录了。

2、数据传输过程因为网络并发量很大在某结点被阻塞
传输过程因为网络并发量很大在某结点被阻塞了,Server端将先后收到2次请求,并持续等待两个Client请求向他发送数据,但是Cient端实际上只有一次请求,而Server端却有2个响应,极端的情况可能由于Client端多次重新发送请求数据而导致Server端最后建立了N多个响应在等待,因而造成极大的资源浪费!

三次握手的seq与ack确定了包的顺序。客户端每次请求时,询问服务端说这是第一号包,服务端收到后告诉客服端下次你给我的只能是二号包(别的都不要),同时给返回到客户端的包作标记:这是我返回给你的一号包。这样,出现阻塞时,根据包的序号就知道要响应的是几号包。

为什么要四次挥手

tcp关闭连接需要四次挥手原因:TCP连接是全双工通道,需要双向关闭。
客户端向服务器关闭请求,表示客户端不再发送数据,服务器响应。此时服务端仍然可以向客户端发送数据,待服务端发送数据结束后,就向客户端发送关闭请求,然后客户端确认。