一篇文章读懂“三次握手”与“四次挥手”

所谓“三次握手”与“四次挥手”,其实就是TCP连接的建立和释放的过程。

三次握手(建立TCP连接)

建立连接之前,客户端主动结束CLOSED阶段,相应地服务器也结束CLOSED阶段并进入LISTEN阶段,然后开始“三次握手”:

  1. 第一次握手
    客户端将包含:
    1)标志位SYN=1(表示“请求建立连接”),
    2)序号seq=x(x为随机数)
    的TCP报文发送给服务器,然后客户端进入SYN_SENT阶段,等待服务器确认。
  2. 第二次握手
    服务器收到客户端发来的请求建立连接的TCP报文,结束LISTEN阶段,将包含:
    1)标识位为SYN=1和ACK=1(表示“确认客服端的报文seq有效,服务器能正常接收客户端发送的数据,并同意创建连接”)
    2)序号seq=y(y为随机数)
    3)确认号ack=x+1(表示“收到客户端的序号seq,并将其值+1作为自己确认号ack的值”)
    的TCP报文返回给客户端,然后服务端进入SYN_RCVD阶段。
  3. 第三次握手
    客户端收到服务器返回的报文后,检查ACK是否为1,ack是否为x+1,如果是,则表明从客户端到服务器的数据传输正常,客户端结束SYN-SENT阶段,并将包含:
    1)标志位ACK=1(表示“收到服务器端同意连接的信号”)
    2)序号seq=x+1(表示“收到服务端的确认号ack,并将其值作为自己序号seq的值”)
    3)确认号ack=y+1(表示“收到服务端的序号seq,并将其值+1作为自己确认号ack的值”)
    的TCP报文返回给服务端,然后客户端进入ESTABLISHED阶段。
    服务器收到来自客户端的TCP报文之后,检查ACK是否为1,如果是,则表明从服务器到客户端的数据传输是正常的。服务端结束SYN_RCVD阶段,进入ESTABLISHED阶段。
    至此,三次握手过程结束,此后客户端与服务器可以进行正常的数据传输。

四次挥手(释放TCP连接)

释放连接之前,客户端主动结束ESTABLISHED阶段,然后开始“四次挥手”:

  1. 第一次挥手
    客户端将包含:
    1)标志位FIN=1(表示“请求释放连接”),
    2)序号seq=x(x为随机数)
    的TCP报文发送给服务器,然后客户端进入FIN_WAIT_1阶段(半关闭状态),并且停止向服务器发送正常连接时的数据,但此时客户端仍然可以接收到服务器发来的数据。
  2. 第二次挥手
    服务器收到客户端发来的请求释放连接的TCP报文,结束ESTABLISHED阶段,将包含:
    1)标识位为ACK=1(表示“接收到客户端发送的释放连接请求”)
    2)序号seq=y(y为随机数)
    3)确认号ack=x+1(表示“收到客户端的序号seq,并将其值+1作为自己确认号ack的值”)
    的TCP报文返回给客户端,然后服务端进入CLOSE_WAIT阶段(半关闭状态)。客户端收到服务器返回的报文后,检查ACK是否为1,ack是否为x+1,如果是,则表明服务器收到了客户端发出的释放连接请求,然后客户端结束FIN_WAIT_1阶段,进入FIN_WAIT_2阶段
  3. 第三次挥手
    服务器自发出确认报文,完成释放服务器到客户端的连接的准备工作后,又一次将包含:
    1)标识位为FIN=1,ACK=1(表示“服务端已经准备好释放连接了”)
    2)序号seq=y(y为随机数)
    3)确认号ack=x+1(表示“收到客户端的序号seq,并将其值+1作为自己确认号ack的值”)
    的TCP报文返回给客户端,然后服务端结束CLOSE_WAIT阶段,进入LAST_ACK阶段,并且停止向客户端发送正常连接时的数据,但此时服务端仍然可以接收到客户器发来的数据。
  4. 第四次挥手
    客户端收到服务器第二次返回的报文后,检查ACK是否为1,ack是否为x+1,如果是,则表明服务端已经准备好释放连接,客户端结束FIN_WAIT_2阶段,并将包含:
    1)标志位ACK=1(表示“收到服务端已经准备好释放连接的信号”)
    2)序号seq=x+1(表示“收到服务端的确认号ack,并将其值作为自己序号seq的值”)
    3)确认号ack=y+1(表示“收到服务端的序号seq,并将其值+1作为自己确认号ack的值”)
    的TCP报文返回给服务端,然后客户端进入TIME_WAIT阶段,开始等待2MSL。
    服务器收到来自客户端的TCP报文之后,检查ACK是否为1,如果是,则表明客户端收到服务端已经准备好释放连接的信号。服务端结束LAST_ACK阶段,进入CLOSED阶段,并正式确认关闭服务器到客户端的连接。客户端等待2MSL后,结束TIME_WAIT阶段,进入CLOSED阶段。
    至此,四次挥手过程结束,客户端与服务器的TCP连接被释放。

客户端什么等待2MSL呢?在此,借用其他道友的解释。
当客户端发出最后的ACK确认报文时,并不能确定服务器端能够收到该段报文。所以客户端在发送完ACK确认报文之后,会设置一个时长为2MSL的计时器。MSL指的是Maximum Segment Lifetime:一段TCP报文在传输过程中的最大生命周期。2MSL即是服务器端发出为FIN报文和客户端发出的ACK确认报文所能保持有效的最大时长。
服务器端在1MSL内没有收到客户端发出的ACK确认报文,就会再次向客户端发出FIN报文;
如果客户端在2MSL内,再次收到了来自服务器端的FIN报文,说明服务器端由于各种原因没有接收到客户端发出的ACK确认报文。客户端再次向服务器端发出ACK确认报文,计时器重置,重新开始2MSL的计时;
否则客户端在2MSL内没有再次收到来自服务器端的FIN报文,说明服务器端正常接收了ACK确认报文,客户端可以进入CLOSED阶段,完成“四次挥手”。

为什么是3次握手,2次可以吗,4次行不行?

为什么是3次

  • 第1次握手:
    客户端什么都不能确认
    服务端确认了对方发送正常
  • 第2次握手:
    客户端确认自己发送/接收正常,对方发送/接收正常
    服务端确认自己接收正常,对方发送正常
  • 第3次握手:
    客户端确认自己发送/接收正常,对方发送/接收正常
    服务端确认自己发送/接收正常,对方发送/接收正常

所以通过3次握手,才能确认双方收发正常。

2次可以吗
2次不可以!
如果第二次不发送SYN+ACK,只是发送确认应答消息ACK,会造成只能建立单向通信,而且不能应答。而TCP是全双工通信的,而且必须保证可靠性。如果第二发送SYN+ACK,不用应答。此时会出现三种情况:

  1. 二次握手失败,C端会重复发送SYN报文,等待对端发送确认报文,S端会保存tcp连接的所有资源,大量的这种情况会导致S资源耗尽。
  2. 二次握手成功,S收不到ACK会重复发送SYN+ACK报文。
  3. 二次握手完以后,双方以为连接建立成功,即可开始通信。假如此时连接并没有真的建立成功,S端开始发送消息,会造成网络拥堵发生。

举例来说:
当A发送一个消息给B,但是由于网络原因,消息被阻塞在了某个节点,然后阻塞的时间超出设定的时间,A会认为这个消息丢失了,然后重新发送消息。
当A和B通信完成后,这个被A认为失效的消息,到达了B。
对于B而言,以为这是一个新的请求链接消息,就向A发送确认;
对于A而言,它认为没有给B再次发送消息(因为上次的通话已经结束)所有A不会理睬B的这个确认,但是B则会一直等待A的消息。
这就导致了B的时间被浪费(对于服务器而言,CPU等资源是一种浪费)。

4次行不行
四次其实原则上来说是可以的,就是把第二次的ACK和SYN分两次发送。在理论上是完全可以行得通的,但是TCP本着节约网络网络资源的前提。还有一种是不拆开二次握手的捎带应答,三次握手之后C端继续发送SYN报文,其时这是徒劳的。第三次完成以后链接已经建立,后面无论多少次都是多余。

为什么建立连接只要3次握手,而断开连接却要4次挥手

TCP是全双工的通信机制,每个方向必须单独进行关闭。
TCP传输连接关闭的原则如下:
当一端完成它的数据发送任务后就可以发送一个FIN字段置1的数据段来终止这个方向的数据发送;当另一端收到这个FIN数据段后,必须通知它的应用层 对端已经终止了那个方向的数据传送。 也许又会问,为什么不能用三次握手中捎带应答机制减少一次握手? TCP是全双工通信的,S收到断开链接请求后只是表示C端不会传输数据到S端了,但是并不表示S端不传输数据到C端。 如果采用捎带应答,S端将无法把剩余的数据传输到C端。

【注】本文为借鉴书籍资料及网络资源的个人总结,欢迎提问与探讨。

猜你喜欢

转载自blog.csdn.net/vale_/article/details/105813490