TCP三次握手与四次挥手
chenpeng 2020-11-29 TCP
①、TCP 报文格式
- TCP 报头中的源端口号和目的端口号与 IP 数据报中的源 IP 和目的 IP 唯一确定一条 TCP 连接,TCP 在发送数据前必须在彼此间建立连接
- 报文主要段的意思:
序号(seq):表示发送的数据字节流,确保TCP传输有序,对每个字节编号确认号(ack):期待收到对方下一个报文段的第一个数据字节的序号,当前报文段最后一个字节的序号加1即为确认号确认(ACK):当 ACK = 1时,确认号有效;当 ACK = 0时,确认号无效同步(SYN):连接建立请求时同步序号,当 SYN = 1时,表示请求连接终止(FIN):用来释放一个连接,当 FIN = 1时,表示此报文段的发送方的数据已经发送完毕,并要求释放连接
②、三次握手过程
建立 TCP 连接时,需要客户端和服务端共发送3个包

- 第一次握手:客户端发送请求标志 SYN = 1 和初始序号 seq = x ,请求建立连接,客户端进入 SYN-SENT 状态
- 第二次握手:服务端发送请求标志 SYN = 1,确认标志 ACK = 1,自己的序号 seq = y,客户端的确认序号 ack = x + 1,服务端进入 SYN-RCVD 状态
- 第三次握手:客户端发送确认标志 ACK = 1,自己的序号 seq = x + 1,服务端的确认序号 ack = y + 1,发送完毕后,客户端和服务端进入 ESTABLISHED(TCP 连接成功)状态,完成三次握手
三次握手过程分析
- 第一次:客户端发送请求到服务端,服务端知道客户端发送,自己接收正常
- 第二次:服务端发送请求到客户端,客户端知道自己发送、接收正常,服务端发送、接收正常
- 第三次:客户端发送请求到服务端,服务端知道客户端发送、接收正常,自己发送、接收也正常
综上所述,握手三次才能使双方都知道自己和对方发送和接收都正常
③、四次挥手过程
释放 TCP 连接时,需要客户端和服务端共发送4个包

- 第一次挥手:客户端发送终止标志 FIN = 1,自己的序号 seq = u,客户端进入 FIN-WAIT-1 状态
- 第二次挥手:服务端接收到客户端的连接释放报文,发送确认标志 ACK = 1,自己的序号 seq = v,客户端的确认号 ack = u + 1,服务端进入 CLOSE-WAIT 状态。这时候处于半关闭状态,客户端已经不再发送数据了,但是服务端若要发送数据,客户端依然要接收
- 第三次挥手:客户端收到服务端的确认结果后,进入 FIN-WAIT-2 状态。服务端发送 终止标志 FIN = 1,确认标志 ACK = 1,自己的序号 seq = w,客户端的确认号 ack = u + 1,服务端进入 LAST-ACK(最后确认)状态,等待客户端的确认
- 第四次挥手:客户端接收到服务端的连接释放报文,发送确认标志 ACK = 1,自己的序号 seq = u + 1,服务端的确认号 ack = w + 1,客户端进入 TIME-WAIT(时间等待)状态。客户端必须经过2MSL(报文最大生存事件)后,才能进入 CLOSED 状态。而服务端只要接收到客户端的确认后,立即进入 CLOSED 状态
四次挥手分析
- 第一次:客户端请求释放连接
- 第二次:服务端确认客户端的释放连接
- 第三次:服务端请求释放连接
- 第四次:客户端确认服务端的释放连接
④、其他问题
为什么建立连接不是两次或四次握手?
- 不是两次的原因:无法确定客户端的接收能力
- 不是四次的原因:建立连接三次握手足够了,再多次用处不大
为什么连接的时候是三次握手,释放的时候是四次挥手?
- 三次握手时,服务端把 SYN 和 ACK 放在一起发送给了客户端
- 四次挥手时,服务端收到客户端的 FIN 报文时,仅仅表示客户端不再发送数据了但是还能接收数据,必须等到所有的报文都发送完毕了,才能发送 FIN,因此先发一个 ACK 表示已经收到客户端的 FIN,延迟一段时间再发送 FIN
为什么客户端最后还要等待2MSL?
- 客户端需要保证最后一次发送的 ACK 报文到达服务端,如果服务端未收到,可以请求客户端重新发送,这样客户端还有时间重发,重启 2MSL 计时
- 1 个 MSL 确保四次挥手中主动关闭方最后的 ACK 报文最终能达到对端
- 1 个 MSL 确保对端没有收到 ACK 重传的 FIN 报文可以到达