TCP 序列号和确认号是如何变化的?( 二 )

数据传输阶段的变化完成了 , 三次握手后,客户端就可以发送第一个 ** **TCP 数据报文了,假设客户端即将要发送 10 字节的数据,流程图下:

TCP 序列号和确认号是如何变化的?

文章插图
在这里插入图片描述
客户端发送 10 字节的数据,通常 TCP 数据报文的控制位是 [PSH, ACK],此时该 TCP 数据报文的序列号和确认号分别设置为:
  • 序列号设置为 client_isn + 1 。客户端上一次发送报文是 ACK 报文(第三次握手),该报文的 seq = client_isn + 1,由于是一个单纯的 ACK 报文,没有携带用户数据,所以 len = 0 。根据公式 1(_序列号 = 上一次发送的序列号 + len_) , 可以得出当前的序列号为 client_isn + 1 + 0 , 即 client_isn + 1 。
  • 确认号设置为 server_isn + 1 。没错 , 还是和第三次握手的 ACK 报文的确认号一样,这是因为客户端三次握手之后,发送 TCP 数据报文 之前,如果没有收到服务端的 TCP 数据报文,确认号还是延用上一次的,其实根据公式 2 你也能得到这个结论 。
可以看到,客户端与服务端完成 TCP 三次握手后,发送的第一个 「TCP 数据报文的序列号和确认号」都是和「第三次握手的 ACK 报文中序列号和确认号」一样的 。
接着,当服务端收到客户端 10 字节的 TCP 数据报文后,就需要回复一个 ACK 报文,此时该报文的序列号和确认号分别设置为:
  • 序列号设置为 server_isn + 1 。服务端上一次发送报文是 SYN-ACK 报文,序列号为 server_isn,根据公式 1(_序列号 = 上一次发送的序列号 + len 。特殊情况,如果上一次发送的报文是 SYN 报文或者 FIN 报文,则改为 + 1_),所以当前的序列号为 server_isn + 1 。
  • 确认号设置为 client_isn + 11。服务端上一次收到的报文是客户端发来的 10 字节 TCP 数据报文,该报文的 seq = client_isn + 1,len = 10 。根据公式 2(_确认号 = 上一次收到的报文中的序列号 + len_),也就是将「收到的 TCP 数据报文中的序列号 client_isn + 1,再加上 10(len = 10) 」的值作为了确认号,表示自己收到了该 10 字节的数据报文 。
之前有读者问 , 如果客户端发送的第三次握手 ACK 报文丢失了,处于 SYN_RCVD 状态服务端收到了客户端第一个 TCP 数据报文会发生什么?
刚才前面我也说了,发送的第一个 「TCP 数据报文的序列号和确认号」都是和「第三次握手的 ACK 报文中序列号和确认号」一样的,并且该 TCP 数据报文也有将 ACK 标记位置为 1 。如下图:
【TCP 序列号和确认号是如何变化的?】
TCP 序列号和确认号是如何变化的?

文章插图
在这里插入图片描述
所以,服务端收到这个数据报文,是可以正常完成连接的建立,然后就可以正常接收这个数据包了 。
四次挥手阶段的变化最后,我们来看看四次挥手阶段中,序列号和确认号的变化 。
数据传输阶段结束后 , 客户端发起了 FIN 报文,请求服务端端开该 TCP 连接,此时就进入了 TCP 四次挥手阶段,如下图 。
TCP 序列号和确认号是如何变化的?

文章插图
在这里插入图片描述
客户端发送的第一次挥手的序列号和确认号分别设置为:
  • 序列号设置为 client_isn + 11 。客户端上一次发送的报文是 [PSH, ACK] ,该报文的 seq = client_isn + 1, len = 10,根据公式 1(_序列号 = 上一次发送的序列号 + len_),可以得出当前的序列号为 client_isn + 11 。
  • 确认号设置为 server_isn + 1 。客户端上一次收到的报文是服务端发来的 ACK 报文,该报文的 seq = server_isn + 1,是单纯的 ACK 报文,不携带用户数据,所以 len 为 0 。那么根据公式 2(确认号 = 上一次收到的序列号 + len) , 可以得出当前的确认号为 server_isn + 1 + 0 (len = 0),也就是 server_isn + 1 。
服务端发送的第二次挥手的序列号和确认号分别设置为: