想一想
大家都知道TCP是全双工的,连接需要三次握手,以保证双方都有收发消息的能力,但是大家有没有理解为什么挥手的时候需要四次呢?
前提知识
先了解下挥手报文标志位
标志位(=1) | 说明 |
---|---|
ACK | 确认标志位,用于数据进行应答确认 |
FIN | 结束标志位,用于关闭连接 |
SYN | 同步标志位,用于建立连接 |
序列号和确认号
序列号(Sequence number):初始序列号是随机的,用来跟踪发送的数据包,下一个序列号=当前序列号+发送数据的字节.
确认号(Acknowledge number):当ACK标志为1时有效,表示期望收到的下一个字节的序号.
四次挥手流程
sequenceDiagram
Client->>Server: (1)FIN, seq=x
Server-->>Client: (2)ACK, ack=x+1, seq=y
Server-->>Client: (3)FIN + ACK, ack=x+1, seq=z
Client-)Server: (4)ACK, ack=z+1, seq=x+1
Client-)Client: 等待2MSL
从四次挥手的流程上看主要有两点不太好理解:
-
第2、3的挥手,为什么不合并一次挥手,这也是为什么挥手是四次的主要原因?
主要原因是因为:当其中一方要关闭的时候,对方可能还有数据要发送,必须等数据发送完成才能关闭链接
由于TCP是全双工的,双方都能相互发送数据,当其中一方要关闭数据(比如Client),发送FIN报文,即要关闭连接,说明client的数据已经发送完毕,发送FIN(1)报文后,client出于FIN-WRITE-1状态,对端(Server)收到FIN报文后,立刻回复ACK(2)报文,然后等待数据发送完毕后,发送FIN+ACK(3)报文,如果把这两个(2)(3)报文合并发送呢?但是由于(3)报文发送时间可能会很长,导致client多次重发 -
为什么要等待2MSL
为了确认发出的ACK报文已经确认被接受,因为如果服务端未收到ACK报文,则会重发FIN报文,如果在2MSL再次收到FIN报文,则再等待2MSL
这里推荐一个好用的记账小程序:墨子记账