Contents

三次握手、四次挥手

一图总结

/static/images/53062591-3d846300-34fc-11e9-8d0f-4063d9ff3398.png

基本概念

消息类型 描述
ACK acknowledge确认标志,为1表示确认号有效,为0表示报文中不包含确认信息,忽略确认号字段。帮助对方确认收到的SYN消息。
SYN synchronize请求同步标志,是建立tcp/ip建立连接的握手信号,用于建立连接过程。在连接请求中。 SYN=1 和 ACK=1。用来初始化和建立连接
FIN Finally结束标志,用于来断开连接。
seq sequance 序列号。
ack acknowledge 确认号。

三次握手

三次握手指建立一个TCP连接时,需要客户端和服务端之间共发送三个包。

它的目的是同步双方的序列号和确认号,交换TCP窗口大小信息。

在socket编程中,客户端执行connect()时,将触发三次握手。

https://pic3.zhimg.com/80/v2-2a54823bd63e16674874aa46a67c6c72_720w.jpg

刚开始客户端处于closed状态,服务器处于listen状态

  • 第一次握手 客户端向服务器发送一个SYN报文,并指明客户端的的序列号seq。
    此时客户端处于SYN_SEND(同步发送)状态
    首部的同步位SYN=1 ,初始序号seq=x,SYN=1的报文段不能携带数据,但要消耗掉一个序号。

  • 第二次握手 服务端收到SYN报文后,会发送自己的SYN/ACK的确认报文作为应答,即SYN=1,ACK=1,并且附带确认号ack=客户端的序号+1,和自己的序列号seq=y。 此时服务器端处于SYN_RCEV(同步接收)状态 在确认报文段中SYN=1 ACK=1,确认号ack=x+1,序号seq=y

  • 第三次握手 客户端收到SYN报文后,会发送一个带ACK的确认包,即ACK=1,ack=服务器的序号+1,附带自己的序列号seq=x+1。 确认报文段ACK=1,确认号ack=y+1,序号seq=x+1,ACK报文段可以携带数据,不携带数据则不消耗序号。 发送完毕后,客户端和服务器进入ESTABLISHED(已建立裂解)状态

为什么不是两次握手

原因:无法确定客户端的接收能力。

四次挥手

四次握手是指TCP断开连接,需要客户端和服务端共发送四个包。
客户端和服务端都可以主动发起挥手动作。

https://pic2.zhimg.com/80/v2-c7d4b5aca66560365593f57385ce9fa9_720w.jpg

刚开始双方都处于ESTABLISHED(已建立)状态。

  • 第一次挥手 客户端发送FIN报文(FIN=1,seq=u),并停止再发送数据,主动关闭TCP连接.
    结束报文中FIN=1,seq=u 此时客户端进入FIN_WAIT1(终止等待1)状态,等待服务端的确认。
  • 第二次挥手 服务器收到FIN之后,会发送ACK报文,表明自己已经收到客户端的报文。把客户端的序号值+1作为ACK报文的序列号值,附带服务端自己的序号值seq=v 确认报文中ACK=1,ack=u+1,seq=v 此时服务端处于 等待关闭CLOSE_WAIT状态。客户端收到后,进入FIN_WAIT2(终止等待2)状态
  • 第三次挥手 服务器端准备好关闭连接时,和客户端的第一次挥手一样,发送FIN/ACK报文,表示确认结束。 结束报文中FIN=1,ACK=1,seq=w,ack=u+1
  • 第四次挥手 客户端收到 FIN 之后,对此发出ACK报文段。 此时客户端处于 TIME_WAIT(时间等待) 状态。 此时TCP未释放掉,需要经过时间等待计时器设置的时间2MSL后,客户端才进入CLOSED状态。而服务器只要收到了客户端发出的确认,立即进入 CLOSED 状态。所以服务器结束 TCP 连接的时间要比客户端早一些。 确认报文中ACK=1,seq=u+1,ack=w+1

等待2MSL的意义

如果不等待会怎样?

如果不等待,客户端直接跑路,当服务端还有很多数据包要给客户端发,且还在路上的时候,若客户端的端口此时刚好被新的应用占用,那么就接收到了无用数据包,造成数据包混乱。所以,最保险的做法是等服务器发来的数据包都死翘翘再启动新的应用。

那,照这样说一个 MSL 不就不够了吗,为什么要等待 2 MSL?

1 个 MSL 确保四次挥手中主动关闭方最后的 ACK 报文最终能达到对端 1 个 MSL 确保对端没有收到 ACK 重传的 FIN 报文可以到达 这就是等待 2MSL 的意义。

为什么是四次挥手而不是三次?

因为服务端在接收到FIN, 往往不会立即返回FIN, 必须等到服务端所有的报文都发送完毕了,才能发FIN。因此先发一个ACK表示已经收到客户端的FIN,延迟一段时间才发FIN。这就造成了四次挥手。

如果是三次挥手会有什么问题?

等于说服务端将ACK和FIN的发送合并为一次挥手,这个时候长时间的延迟可能会导致客户端误以为FIN没有到达客户端,从而让客户端不断的重发FIN。

详解:

https://zhuanlan.zhihu.com/p/86426969

https://mp.weixin.qq.com/s/JBsqCQAouQ6hH7gcvtYMLg

神三元

https://juejin.cn/post/6844903731704791054