Wireshark网络协议分析 - TCP协议
在我的博客阅读本文
文章目录
- 1. 基础
- 2. 实战
- 2.1. 用Go写一个简单的TCP服务器与客户端
- 2.2. Wireshark抓包分析
- 2.3. 限制数据包的大小——MSS与MTU
- 2.4. 保证TCP的有序传输——Seq,Len与Ack
- 2.5. TCP头标志位——URG,ACK,PSH,RST,SYN,FIN
- 2.6. TCP连接建立——三次握手
- 2.7. TCP连接释放——四次挥手
- 2.8. 大包拆分——累计确认,TCP窗口
- 2.9. 动态调整TCP窗口——从慢启动到阻塞避免
- 2.10. 丢包问题——RTO与快速重传
- 2.11. 减轻网络负担可能降低性能——延迟确认与Nagle算法
- 3. 参考资料
1. 基础
根据TCP/IP四层模型,在TCP场景下如下图:

其中,TCP头的信息:

2. 实战
2.1. 用Go写一个简单的TCP服务器与客户端
要分析TCP协议,尽管可以直接使用一个http的访问进行抓包,但是http的过程中又涉及DNS,ARP等过程混淆我们,为了纯粹的分析TCP协议,我们这里使用Golang写了一个简单的9830端口的TCP服务器与客户端,源代码简单展示如下:
服务端:
package serverimport ("fmt""net""os""strings""test/util"
)func StartTCPServer(c chan<- string) {listener, err := net.Listen("tcp", "localhost:9830")if err != nil {util.HandleError(err)os.Exit(1)}defer listener.Close()c <- "ready"// 等待连接conn, err := listener.Accept()if err != nil {util.HandleError(err)os.Exit(1)}// 处理连接handleRequest(conn)
}func handleRequest(conn net.Conn) {defer conn.Close()var res strings.Builderbuf := make([]byte, 1024)for {n, err := conn.Read(buf)if err != nil {break}res.Write(buf[:n])}fmt.Print("Received client message, size:", res.Len())
}
客户端:
package clientimport ("fmt""net""os""strings""test/util"
)func StartTCPClient() {conn, err := net.Dial("tcp", "localhost:9830")if err != nil {util.HandleError(err)os.Exit(1)}defer conn.Close()// 发送200kb消息largeMessage := strings.Repeat("A", 200*1024)_, err = conn.Write([]byte(largeMessage))if err != nil {util.HandleError(err)os.Exit(1)}fmt.Println("Sent message to server!")
}
执行入口:
package mainimport ("fmt""sync"c "test/internal/client"s "test/internal/server"
)// main wireshark filter express: tcp.port==9830
func main() {var wg sync.WaitGroupwg.Add(2)serverReady := make(chan string, 1)go func() {s.StartTCPServer(serverReady)wg.Done()}()go func() {<-serverReadyc.StartTCPClient()wg.Done()}()wg.Wait()
}
编译执行,控制台输出如下:

2.2. Wireshark抓包分析
由于我们这里TCP的客户端和服务端都是面向localhost ,使用adapter for loopback traffic capture接口捕获回环流量,过滤器过滤tcp端口9830即可:
tcp.port==9830

需要注意,即使代码和我一样,最终抓包的数据依然会有差距,因为MTU,window size等参数会因为OS的策略不同有差异,求同存异抓共性。
大体分为三部分:
- 协议连接建立与确认:即包号92~96部分,图中具体又分为两部分:
- 包号92~93中的Source和Destination都是::1,这个地址是IPV6的地址,类似于IPV4中的127.0.0.1。TCP客户端先尝试了连接IPV6的9830端口,被服务器中断(RST)。
- 包号94~96尝试了尝试了IPV4的9803端口,这一次得到了服务器的正确回应,开始了**
TCP协议中的“三次握手”,此时建立TCP连接**
- 具体的业务数据交互:即包号97~103
- 协议连接断开与确认:即包号104~107,也就是**
TCP协议中的“四次挥手”,此时释放TCP连接**
点开包号96,我们查看其Network层的数据情况:

Source Port之类的字段比较直观易于理解,下面我们重点看一下一些不太直观的字段代表的数据含义。
2.3. 限制数据包的大小——MSS与MTU
网络对包的大小是存在限制的,这部分是在建立TCP连接的“三次握手”中进行声明,即:
MSS(Maximum Segment Size,最大段大小)MTU(Maximum Transmission Unit,最大传输单元):MSS+TCP头长度 +IP头长度即是MTU

在“三次握手中”,包号94中,客户端向服务端声明了MSS=65495 ,可以计算MTU(单位为Byte,一般Wireshark中出现的数字单位都是Byte):
MTU = 65495 + 20(TCP头) + 20(IP头) = 65535
同理,包号95中,服务端在给客户端的ACK包中也声明了自己的MSS,也可以计算出MTU。
客户端和服务端各自有MTU,实际的传输包的大小是由客户端与服务端2个MTU中较小的数值去决定的。
2.4. 保证TCP的有序传输——Seq,Len与Ack
TCP提供的是有序传输,每个数据段都要标上一个序号。
在实际场景中,TCP传输数据时并不能严格保证有序,总会出现乱序的情况,需要根据序号进行排序。
Len:length,数据长度Seq:Sequence Number,序号,即上一个数据段Seq+Len,发送方和接收方都需各自维护Seq状态Ack:Acknowledge Number,确认号,待接受的数据序号,发送方和接收方都需各自维护Ack状态
以包号97~99为例:

- 97号:客户端发送数据,声明自己的
Seq=1,Len=65495 - 98号:服务端声明自己的
Seq=1,Len=0,同时计算Ack=65496,即发送方的Seq+Len - 99号:客户端发送数据,声明自己的
Seq=65496,Len=65495,ACK为1,即上一步中服务端的Seq+Len
可以推断出:
Seq和Len主要表达的是作为发送方当前的数据序号和长度Ack主要表达的是作为接收方的接收到的数据序号和长度的和TCP通信中,一个客户端/服务端既有发送的场景,也有接受的场景,因此Seq,和Ack都各自需要单独维护,Len则是实际的数据长度。
2.5. TCP头标志位——URG,ACK,PSH,RST,SYN,FIN
TCP头包含一系列的标识位(也称作控制位或标志位),它们用于控制和管理TCP连接的不同方面。每个标识位都占用TCP头部中的1个比特。
Wireshark不仅帮我们“翻译”了当前封包的状态,也把TCP头的所有状态位都做了提示。

- URG(紧急):表示紧急指针字段(Urgent Pointer)有效,用于指示紧急数据。
- ACK(确认):表示确认字段(Acknowledgment Field)有效。几乎所有的TCP报文,除了最初的SYN报文外,都会设置这个标志。
- PSH(推送):提示接收端应该立即将这个报文交给应用层,而不是等待缓冲区满。
- RST(重置):用于重置错误的连接,或拒绝非法的报文或打开的连接。
- SYN(同步):在建立连接时用来同步序列号。当一个连接开始时,用来初始化序列号并开始连接建立。
- FIN(结束):用于释放一个连接。当数据传输结束时,发送方用它来告诉接收方它已经结束发送数据。
2.6. TCP连接建立——三次握手
包号94~96行则为TCP的“三次握手”行为,发生在TCP连接建立之初:

“三次握手”主要分为3步:
- 客户端 → 服务端:【SYN】申请建立连接,声明初始
Seq - 服务端 → 客户端:【SYN,ACK】收到连接请求,声明初始
Seq,声明Ack=客户端声明的初始Seq+ 1 - 客户端 → 服务端:【ACK】收到确认请求,声明
Ack=服务端初始Seq+ 1
2.7. TCP连接释放——四次挥手
包号104~107行则为TCP的“四次挥手”行为,发生在TCP连接需要中断,释放连接时:

**“四次挥手”**主要分为4步,发起方可能是客户端,也可能是服务端:
- 发起方发起释放连接请求:【FIN,ACK】,声明
Seq和Ack - 接受方返回确认收到:【ACK】,声明
Ack=第1.步中发起方的Seq+ 1 - 接收方发起释放连接请求:【FIN,ACK】,声明
Seq和Ack(与上一步一样) - 发起方返回确认收到:【ACK】,声明
Ack=第3.步中接收方的Seq+ 1
2.8. 大包拆分——累计确认,TCP窗口
- 我们
TCP客户端代码中发送了一个200kb的字符串给服务端,之前分析过我们的MTU限制在65535b,不算TCP头和IP头的MSS为65495b。我们实际无法在一个数据帧中发送全部数据,需要按照MTU拆分为多个数据帧进行发送。 - 多个数据帧的发送不一定每一条都需要等待接收方回复ACK,可以发送若干条数据帧之后,接收方回复一条ACK即可,这是TCP的累计确认。
TCP连接的一方连续发送的数据帧数是存在限制的,否则无限发送数据帧,另一方处理速率赶不上就会遇到Back Pressure(背压)的情况,这个限制则是TCP Window(TCP窗口),即Wireshark中的Win的数值:

- 包号95是三次握手的第二次,win=65535,这是声明自己的接受窗口大小是65535,在我们的例子中是服务端声明自己的接受窗口大小是65535,这是协商的初始窗口大小。
- 客户端按照
MTU/MSS要求拆分数据帧 - 包号97,客户端向服务端发送了
Len=65495的数据 - 包号98,服务端向客户端发送
ACK,调整了自己的TCP窗口,声明Win=2161152。这里如果窗口大小为零,发送方将停止发送数据,并等待下一个窗口更新。也就是说,窗口大小是动态调整的。 - 客户端获知服务端的窗口变大了,因此自己可以连续发送多个数据帧
- 包号99~101,客户端连续向服务端发送了3个数据帧,无需等待服务端回复
ACK,Seq按序增加,由于服务端没有回复ACK,这3帧数据的Ack都一样为1。 - 包号102,服务端向客户端发送了
ACK,Ack=204801,刚好是包号101的Seq+len,这里实际上代表当前客户端已经收到了包号99~101的内容,这被称为TCP的累计确认。
窗口大小在TCP协议设计之初只留了2byte,这个可以在Wireshark中看到:

后续为了提升Wireshark的长度,在TCP“三次握手”时的Options中有Window scale :

最终窗口大小计算公式 = Window的数值 8442 * 2的window scale次方
2.9. 动态调整TCP窗口——从慢启动到阻塞避免
在上一部分大包拆分中,可以看到TCP窗口是会动态调整的,这是有一个具体的调整策略的。
- 连接刚建立,发送方对网络情况一无所知,需要定一个初始值,可以是几个MSS大小。
- 连接初期,由于发生拥塞概率很低,如果发出去的包都得到确认,可以尝试增大阻塞窗口,RFC建议是每收到n个确认,阻塞窗口就增大n个MSS,这个过程需要慢慢增长,称为慢启动过程。
- 持续一段时间后,窗口大小达到一个较大的值,发生拥塞的概率变大,不能继续使用慢启动的算法,需要再缓慢一点,RFC建议每个往返时间增加1个MSS,这个过程称为拥塞避免。

2.10. 丢包问题——RTO与快速重传
TCP连接过程中有可能出现丢包的情况。
对于发送方来说,如果发出去的包不像往常一样得到确认,有可能是网络延迟导致,发送方会等待一段时间再去判断,如果一直收不到,就会判定包已丢失,进行重传。这个过程称为超时重传,从发出原始包刀重传该包的时间段称为RTO:

重传之后,TCP窗口也会被调整,会先降到1个MSS,之后会进入慢启动过程。不过这次从慢启动到拥塞的临界窗口值有了参考依据,RFC5681建议应该设置为拥塞时没被确认的数据量的1/2,不小于2个MSS:

RTO的过程对性能影响是比较大的:
- RTO阶段等待重传不能传数据,浪费处理时间
- RTO之后的TCP窗口急剧减小,传输比之前慢
与RTO不同,如果拥塞很轻微,发生部分丢包,发送方还是能接收到部分Ack包,Ack会有期望Seq号,通过这个期望Seq号,发送方会意识到发生包丢失,当发送方收到3个及以上Dup Ack(重复确认)时会立刻重传,这个过程称为快速重传。
这里之所以需要凑齐3个及以上Dup Ack的原因是实际场景中包可能会乱序,Ack好像表现出一个缺失的包,但是这个包并没有丢失,而是由于乱序还在数据传输路上,可能很快就会传输过来,因此设置一个数量要求一定程度避免乱序导致快速重传:

快速重传的过程对性能影响是比较小的,因为依然有部分包能够被发送和接收到,说明拥塞并不严重,因此只需传慢一点即可,无需突然大幅度TCP窗口重新慢启动。RFC5681建议重新设置临时窗口为拥塞时没被确认数据的1/2,不小于2个MSS,拥塞窗口设置为临界窗口+3个MSS

2.11. 减轻网络负担可能降低性能——延迟确认与Nagle算法
- 延迟确认:如果收到一个包后暂时没什么数据要发给对方,那就延迟一段时间再确认;假设这段时间内恰好有数据要发出,则确认信息和数据可以在一个包里发。延迟确认减少了部分确认包,减轻了网络负担,但有时候会影响性能,带来传输数据延迟。
- Nagle算法:在发出去的数据还没有被确认之前,如果有小数据生成,就把小数据收集起来凑满一个MSS或者等收到确认后再发送。
3. 参考资料
- 林沛满 -《Wireshark网络分析就这么简单》
- 刘超 ——《趣谈网络协议》
相关文章:
Wireshark网络协议分析 - TCP协议
在我的博客阅读本文 文章目录 1. 基础2. 实战2.1. 用Go写一个简单的TCP服务器与客户端2.2. Wireshark抓包分析2.3. 限制数据包的大小——MSS与MTU2.4. 保证TCP的有序传输——Seq,Len与Ack2.5. TCP头标志位——URG,ACK,PSH,RST&…...
3 款最好的电脑硬盘数据迁移软件
您将从本页了解 3 款最好的 SSD硬盘数据迁移软件,磁盘供应商提供的软件和可靠的第三方软件。仔细阅读本文并做出您的选择。 什么是数据迁移? 数据迁移是将数据移动到其他计算机或存储设备的过程。在日常工作活动中,常见的数据迁移有三种&…...
【Java之HTML】
HTML 概念 互联网的产生:w3c的成立, 互联网最开始设计的目的:看论文 ---->浏览器,HTML 网络三要素:HTML HTTP URL HTML描述论文的格式 HTTP标记这个论文在网络上怎么传输 URL:指示这个论文在互联网的哪…...
支付宝支付功能解析,从零到掌握,轻松享受便捷支付
目录 一、支付宝支付功能简介 1.1 支付宝支付的概念 1.2 支付宝支付的优势 1.3 支付宝支付的适用场景 二、支付宝支付的准备工作 三、支付宝支付的接入流程 四、支付宝支付的安全性 5.1 支付宝支付的安全机制 5.2 防范支付风险的措施 5.3 支付宝支付的安全技术保障 …...
MacOS安装反编译工具JD-GUI以及解决无法打开的问题
目录 一.下载地址 二.安装 三.问题 四.解决办法 1.显示包内容 2.找到Contents/MacOS/universalJavaApplicationStub.sh 3.修改sh文件 4.保存后再次打开即可 一.下载地址 Java Decompiler 二.安装 将下载下来的 jd-gui-osx-1.6.6.tar 解压,然后将 JD-GUI.a…...
SpringBoot将第三方的jar中的bean对象自动注入到ioc容器中
新建一个模块,做自动配置 config:需要准备两个类,一个自动配置类,一个配置类 CommonAutoConfig:此类用于做自动配置类它会去读取resoutces下的META-INF.spring下的org.springframework.boot.autoconfigure.AutoConfig…...
5.变量的解构赋值 - JS
什么是解构赋值 通过类似(或相同)的构型,将已知数据的元素/属性解构并提取出来,再赋值到相应变量,可以是新建的变量,也可以是已存在的变量/属性等;最常见的是数组和对象的解构赋值,…...
tableau添加形状
目录 1.效果:1.自带的形状:2.添加形状:小结: 1.效果: 1.自带的形状: 2.添加形状: 找到tableau的安装目录,点入 默认->形状 的文件夹: 新建一个文件夹: …...
(2)(2.10) LTM telemetry
文章目录 前言 1 协议概述 2 配置 3 带FPV视频发射器的使用示例 4 使用TCM3105的FSK调制解调器示例 前言 轻量级 TeleMetry 协议 (LTM) 是一种单向通信协议(从飞行器下行的数据链路),可让你以低带宽/低波特率(通常为 2400 波…...
工具推荐系列-极客编辑器(实时在线编写md文件同步GitHub)
工具项目地址:https://github.com/geekeditor/geekeditor-desktop-releases/tree/main 工具基础配置方法:https://www.geekeditor.com/workspace1.x.html 详细同步代码仓的方法可以用下面: 如何创建GitHub仓库 及生成获取AccessToken…...
3d gaussian splatting介绍整理
3D 高斯分布是用于实时辐射场渲染的 3D 高斯分布中描述的一种光栅化技术,它允许实时渲染从小图像样本中学习到的逼真场景。 paper github 本文翻译整理自: blog: Introduction to 3D Gaussian Splatting DDPMs - Part 2 给出一些2D图片,用…...
[C#]de4dot常用命令
命令:de4dot.exe "D:\xxx.exe" 解释:运行后文件在程序集的目录下生成一个带-cleaned的新程序集。 命令:de4dot.exe file1 -f "D:\xxx.exe" -o "D:\output\xxx_cleaned.exe" 解释:-f : 指定.NET 程序…...
林浩然的“生命体验”大冒险
林浩然的“生命体验”大冒险 Lin Haoran’s “Life Experience” Grand Adventure 在一个阳光明媚的日子,林浩然——我们这位幽默风趣、充满生活智慧的大男孩,正坐在自家后院的老槐树下,手捧一本哲学书,皱着眉头深思:“…...
设计模式——职责链模式(Chain of Responsibility Pattern)
概述 职责链模式(Chain of Responsibility Pattern):避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。职责链模式是一种对象行为…...
C++引用详解
顾得泉:个人主页 个人专栏:《Linux操作系统》 《C/C》 《LeedCode刷题》 键盘敲烂,年薪百万! 一、引用的概念 引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间…...
fMRI数据处理(随时更新)
要开始学习处理fMRI的数据了。 fMRI的数据一般有 dcm 格式和 nii 格式。 Nifti(Neuroimaging Informatics Technology Initiative,神经影像信息学技术倡议)文件格式,是目前各大神经影像分析工具普遍兼容的体素水平的数据格式&am…...
【Linux C | 网络编程】getsockname 和 getpeername函数详解及C语言例子
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…...
研发日记,Matlab/Simulink避坑指南(六)——字节分割Bug
文章目录 前言 背景介绍 问题描述 分析排查 解决方案 总结归纳 前言 见《研发日记,Matlab/Simulink避坑指南(一)——Data Store Memory模块执行时序Bug》 见《研发日记,Matlab/Simulink避坑指南(二)——非对称数据溢出Bug》…...
(M)unity受伤反弹以及死亡动画
受伤反弹 1.在人物控制脚本中添加受伤后速度将为0,并添加一个反弹的力 在刷新移动时,需要在没有受伤的状态 public bool isHurt; public float hurtForce; private void FixedUpdate() {if(!isHurt)Move(); }public void GetHurt(Transform attacker) …...
【Java】Springboot入门
学习目标 基于SpringBoot框架的程序开发步骤 熟练使用SpringBoot配置信息修改服务器配置 基于SpringBoot的完成SSM整合项目开发 一、SpringBoot简介 1. 入门案例 问题导入 SpringMVC的HelloWord程序大家还记得吗? SpringBoot是由Pivotal团队提供的全新框架&…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
