TCP 序列号和确认号是如何变化的?
大家好,我是小林。
在网站上回答了很多人的问题,我发现很多人对 TCP 序列号和确认号的变化都是懵懵懂懂的,只知道三次握手和四次挥手过程中,ACK 报文中确认号要 +1,然后数据传输中 TCP 序列号和确认号的变化就不知道了。
也有很多同学跟我反馈,希望我写一篇关于 TCP 序列号和确认号变化过程的文章。大家别小看这个基础知识点,其实很多人都不知道的。
所以,这次就跟大家聊聊以下过程中,TCP 序列号和确认号是如何变化的?
- 三次握手中 TCP 序列号和确认号的变化
- 数据传输中 TCP 序列号和确认号的变化
- 四次挥手中 TCP 序列号和确认号的变化
万能公式
我根据经验总结了一条万能公式。
发送的 TCP 报文:
- 公式一:序列号 = 上一次发送的序列号 + len(数据长度)。特殊情况,如果上一次发送的报文是 SYN 报文或者 FIN 报文,则改为 上一次发送的序列号 + 1。
- 公式二:确认号 = 上一次收到的报文中的序列号 + len(数据长度)。特殊情况,如果收到的是 SYN 报文或者 FIN 报文,则改为上一次收到的报文中的序列号 + 1。
可能有点抽象,接下来举一些实际的场景,加深对这个万能公式的理解。
先给大家看看 TCP 序列号和确认号在 TCP 头部的哪个位置。可以看到,这两个字段都是 32 位。
这里重点关注这三个字段的作用:
- 序列号:在建立连接时由内核生成的随机数作为其初始值,通过 SYN 报文传给接收端主机,每发送一次数据,就「累加」一次该「数据字节数」的大小。用来解决网络包乱序问题。
- 确认号:指下一次「期望」收到的数据的序列号,发送端收到接收方发来的 ACK 确认报文以后,就可以认为在这个序号以前的数据都已经被正常接收。用来解决丢包的问题。
- **控制位:**用来标识 TCP 报文是什么类型的报文,比如是 SYN 报文、数据报文、ACK 报文,FIN 报文等。
三次握手阶段的变化
先来说说三次握手中 TCP 序列号和确认号的变化。
假设客户端的初始化序列号为 client_isn,服务端的初始化序列号为 server_isn,TCP 三次握手的流程如下:
在这里我们重点关注,下面这两个过程。
服务端收到客户端的 SYN 报文后,会将 SYN-ACK 报文(第二次握手报文)中序列号和确认号分别设置为:
- 序列号设置为服务端随机初始化的序列号 server_isn。
- 确认号设置为 client_isn + 1,服务端上一次收到的报文是客户端发来的 SYN 报文,该报文的 seq = client_isn,那么根据公式 2(确认号 = 上一次收到的报文中的序列号 + len。特殊情况,如果收到的是 SYN 报文或者 FIN 报文,则改为 + 1),可以得出当前确认号 = client_isn + 1。
客户端收到服务端的 SYN-ACK 报文后,会将 ACK 报文(第三次握手报文)中序列号和确认号分别设置为:
- 序列号设置为 client_isn + 1。客户端上一次发送报文是 SYN 报文,SYN 的序列号为 client_isn,根据公式 1(序列号 = 上一次发送的序列号 + len。特殊情况,如果上一次发送的报文是 SYN 报文或者 FIN 报文,则改为 + 1),所以当前的序列号为 client_isn + 1。
- 确认号设置为 server_isn + 1,客户端上一次收到的报文是服务端发来的 SYN-ACK 报文,该报文的 seq = server_isn,那么根据公式 2(确认号 = 收到的报文中的序列号 + len。特殊情况,如果收到的是 SYN 报文或者 FIN 报文,则改为 + 1),可以得出当前确认号 = server_isn + 1。
为什么第二次和第三次握手报文中的确认号是将对方的序列号 + 1 后作为确认号呢?
SYN 报文是特殊的 TCP 报文,用于建立连接时使用,虽然 SYN 报文不携带用户数据,但是 TCP 将 SYN 报文视为 1 字节的数据,当对方收到了 SYN 报文后,在回复 ACK 报文时,就需要将 ACK 报文中的确认号设置为 SYN 的序列号 + 1 ,这样做是有两个目的:
- 告诉对方,我方已经收到 SYN 报文。
- 告诉对方,我方下一次「期望」收到的报文的序列号为此确认号,比如客户端与服务端完成三次握手之后,服务端接下来期望收到的是序列号为 client_isn + 1 的 TCP 数据报文。
数据传输阶段的变化
完成了,三次握手后,客户端就可以发送第一个 ** **TCP 数据报文了,假设客户端即将要发送 10 字节的数据,流程图下:
客户端发送 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。如下图:
所以,服务端收到这个数据报文,是可以正常完成连接的建立,然后就可以正常接收这个数据包了。
四次挥手阶段的变化
最后,我们来看看四次挥手阶段中,序列号和确认号的变化。
数据传输阶段结束后,客户端发起了 FIN 报文,请求服务端端开该 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。
服务端发送的第二次挥手的序列号和确认号分别设置为:
- 序列号设置为 server_isn + 1。服务端上一次发送的报文是 ACK 报文,该报文的 seq = server_isn + 1,而该报文是单纯的 ACK 报文,不携带用户数据,所以 len 为 0,根据公式 1(序列号 = 上一次发送的序列号 + len),可以得出当前的序列号为 server_isn + 1 + 0 (len = 0),也就是 server_isn + 1。
- 确认号设置为 client_isn + 12。服务端上一次收到的报文是客户端发来的 FIN 报文,该报文的 seq = client_isn + 11,根据公式 2(_确认号= 上一次_收到的序列号 + len,特殊情况,如果收到报文是 SYN 报文或者 FIN 报文,则改为 + 1),可以得出当前的确认号为 client_isn + 11 + 1,也就是 client_isn + 12。
服务端发送的第三次挥手的序列号和确认号还是和第二次挥手中的序列号和确认号一样。
- 序列号设置为 server_isn + 1。
- 确认号设置为 client_isn + 12。
客户端发送的四次挥手的序列号和确认号分别设置为:
- 序列号设置为 client_isn + 12。客户端上一次发送的报文是 FIN 报文,该报文的 seq = client_isn + 11,根据公式 1(序列号 = 上一次发送的序列号 + len。特殊情况,如果收到报文是 SYN 报文或者 FIN 报文,则改为 + 1),可以得出当前的序列号为 client_isn + 11 + 1,也就是 client_isn + 12。
- 确认号设置为 server_isn + 2。客户端上一次收到的报文是服务端发来的 FIN 报文,该报文的 seq = server_isn + 1,根据公式 2(_确认号 = 上一次_收到的序列号 + len,特殊情况,如果收到报文是 SYN 报文或者 FIN 报文,则改为 + 1),可以得出当前的确认号为 server_isn + 1 + 1,也就是 server_isn + 2。
实际抓包图
在这里贴一个,实际过程中的抓包图。
套入我的万能公式,发送的 TCP 报文:
- 公式一:序列号 = 上一次发送的序列号 + len(数据长度)。特殊情况,如果上一次发送的报文是 SYN 报文或者 FIN 报文,则改为 上一次发送的序列号 + 1。
- 公式二:确认号 = 上一次收到的报文中的序列号 + len(数据长度)。特殊情况,如果收到的是 SYN 报文或者 FIN 报文,则改为上一次收到的报文中的序列号 + 1。
懂了这套公式之后,相信你在看这类的抓包图中序列号和确认号的变化的时候,就不会没有逻辑了。
怎么样,学废了吗,溜啦溜啦!
更多网络文章
网络基础篇
- TCP/IP 网络模型有哪几层?
- 键入网址到网页显示,期间发生了什么?
- Linux 系统是如何收发网络包的?
HTTP 篇
- HTTP 常见面试题
- HTTP/1.1如何优化?
- HTTPS RSA 握手解析
- HTTPS ECDHE 握手解析
- HTTPS 如何优化?
- HTTP/2 牛逼在哪?
- HTTP/3 强势来袭
- 既然有 HTTP 协议,为什么还要有 RPC?
TCP 篇
- TCP 三次握手与四次挥手面试题
- TCP 重传、滑动窗口、流量控制、拥塞控制
- TCP 实战抓包分析
- TCP 半连接队列和全连接队列
- 如何优化 TCP?
- 如何理解是 TCP 面向字节流协议?
- 为什么 TCP 每次建立连接时,初始化序列号都要不一样呢?
- SYN 报文什么时候情况下会被丢弃?
- 四次挥手中收到乱序的 FIN 包会如何处理?
- 在 TIME_WAIT 状态的 TCP 连接,收到 SYN 后会发生什么?
- TCP 连接,一端断电和进程崩溃有什么区别?
- 拔掉网线后, 原本的 TCP 连接还存在吗?
- tcp_tw_reuse 为什么默认是关闭的?
- HTTPS 中 TLS 和 TCP 能同时握手吗?
- TCP Keepalive 和 HTTP Keep-Alive 是一个东西吗?
- TCP 有什么缺陷?
- 如何基于 UDP 协议实现可靠传输?
- TCP 和 UDP 可以使用同一个端口吗?
- 服务端没有 listen,客户端发起连接建立,会发生什么?
- 没有 accpet,可以建立 TCP 连接吗?
- 用了 TCP 协议,数据一定不会丢吗?
IP 篇
- IP 基础知识全家桶
- ping 的工作原理
TCP 序列号和确认号是如何变化的?相关推荐
- 计算机网络---TCP序列号和确认号
写在前面: 在网络分析中,读懂TCP序列号和确认号在的变化趋势,可以帮助我们 学习TCP协议以及排查通讯故障,如通过查看序列号和确认号可以确定数据传输是否乱序. 1. 序列号和确认号的简介及作用 TC ...
- 通过wireshark理解TCP序列号和确认号
如果你正在读这篇文章,很可能你对TCP"非著名"的"三次握手"或者说"SYN,SYN/ACK,ACK"已经很熟悉了.不幸的是,对很多人来说, ...
- TCP序列号和确认号
这里分两种情况来讲: 一.三次握手 第1步:客户端向服务器发送一个同步数据包请求建立连接,该数据包中,初始序列号(ISN)是客户端随机产生的一个值,确认号是0: 第2步:服务器收到这个同步请求数据包后 ...
- TCP三次握手的序列号和确认号
第一次握手:客户端发送:序列号是随机数x: 第二次握手:服务端回:序列号随机数y,确认号x+1: 第三次握手:客户端回:序列号x+1,确认号y+1
- 理解TCP序列号(Sequence Number)和确认号(Acknowledgment Number)
原文见:http://packetlife.net/blog/2010/jun/7/understanding-tcp-sequence-acknowledgment-numbers/ from:ht ...
- 转:理解TCP序列号(Sequence Number)和确认号(Acknowledgment Number)
http://blog.csdn.net/a19881029/article/details/38091243 原文见:http://packetlife.net/blog/2010/jun/7/un ...
- 对tcp三次握手的详解之 理解TCP序列号(Sequence Number)和确认号(Acknowledgment Number)
重要 !!!!!!!!! 转载自[怀揣梦想,努力前行] 对tcp三次握手的详解之 理解TCP序列号(Sequence Number)和确认号(Acknowledgment Number) ...
- TCP标志位syn,ack,fin以及序列号(seq),响应号(ack)
一,三次握手 TCP使用三次握手建立一个连接: 第一次握手:客户端发送SYN包至服务器,并进入SYN_SENT状态,等待服务器确认 第二次握手:服务器收到客户端的SYN包,发送一个ACK,同时发送自己 ...
- TCP头部分析与确认号的理解
TCP头部分析与确认号的理解 https://www.cnblogs.com/xcywt/p/8075623.html TCP协议(1)--TCP首部 https://blog.csdn.net/la ...
最新文章
- 【线段树合并】解题报告:luogu P4556雨天的尾巴 (树上对点差分 + 动态开点 + 线段树合并)线段树合并模板离线/在线详解
- will_paginate 用作查询分页的注意事项
- 一文看尽飞桨PaddlePaddle最新升级:5大优势,更低门槛使用深度学习
- IOS开发之----异常处理
- 对路径的访问被拒绝怎么办_学习了解ACL—扩展访问控制列表,就在网工知识角...
- Nginx负载均衡策略之url_hash
- Struts2+Spring+Hibernate环境搭建
- mysql磁盘无法挂载,linux – 无法挂载磁盘(VFS:找不到ext4文件系统)
- Acoustica 7 Premium Edition for Mac(音频处理软件) v7.3.28
- leetcode 35. 搜索插入位置(二分法搜索失败的情况)
- 20172315 2018-2019-1《程序设计与数据结构》课程总结
- P1018 乘积最大(高精度加/乘)
- vue ajax 上传,vue中用ajax上传文件
- graphviz安装
- python如何用色度表示数值大小_Python人体肤色检测
- 用PS抠图做电子签名
- 深圳大学计算机与科学考研科目,2020深圳大学计算机专业课不考408了
- 30ea什么意思_ea阶段是什么?你未必全知道!
- post 防篡改_Cookie防篡改机制
- 基于人工智能推理的英特尔® 精选解决方案
热门文章
- Mac mtr 网络分析工具安装
- 【Window10配置3080ti的深度学习环境(Anaconda+cuda11.4+pytorch1.11+pycharm)】
- 《互联网理财一册通》一一12.3 微信理财通
- 我的博客园主页、公众号
- 双击 计算机 网络打不开,win10系统双击“计算机”打不开的处理步骤
- 严蔚敏数据结构——建图,DFS,BFS,拓扑排序
- 《雍正皇帝》文化专有词泰译研究(研究综述)
- 五行和五脏(《走近中医》摘抄)
- 错觉图片生成实验 - 不同步的方块
- 为什么数据透视表不能分组_问题分组数据透视表项