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场景下如下图:

Untitled

其中,TCP头的信息:

Untitled

2. 实战

2.1. 用Go写一个简单的TCP服务器与客户端

要分析TCP协议,尽管可以直接使用一个http的访问进行抓包,但是http的过程中又涉及DNSARP等过程混淆我们,为了纯粹的分析TCP协议,我们这里使用Golang写了一个简单的9830端口的TCP服务器与客户端,源代码简单展示如下:

服务端:

package server

import (
	"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.Builder
	buf := 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 client

import (
	"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 main

import (
	"fmt"
	"sync"
	c "test/internal/client"
	s "test/internal/server"
)

// main wireshark filter express: tcp.port==9830
func main() {
	var wg sync.WaitGroup
	wg.Add(2)
	serverReady := make(chan string, 1)

	go func() {
		s.StartTCPServer(serverReady)
		wg.Done()
	}()

	go func() {
		<-serverReady
		c.StartTCPClient()
		wg.Done()
	}()

	wg.Wait()
}

编译执行,控制台输出如下:

Untitled

2.2. Wireshark抓包分析

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

tcp.port==9830

Untitled

需要注意,即使代码和我一样,最终抓包的数据依然会有差距,因为MTUwindow 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层的数据情况:

Untitled

Source Port之类的字段比较直观易于理解,下面我们重点看一下一些不太直观的字段代表的数据含义。

2.3. 限制数据包的大小——MSS与MTU

网络对包的大小是存在限制的,这部分是在建立TCP连接的“三次握手”中进行声明,即:

  • MSS(Maximum Segment Size,最大段大小)
  • MTU(Maximum Transmission Unit,最大传输单元):MSS+ TCP头长度 + IP头长度即是MTU

Untitled

在“三次握手中”,包号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为例:

Untitled

  • 97号:客户端发送数据,声明自己的Seq=1,Len=65495
  • 98号:服务端声明自己的Seq=1,Len=0,同时计算Ack=65496,即发送方的Seq + Len
  • 99号:客户端发送数据,声明自己的Seq=65496,Len=65495,ACK为1,即上一步中服务端的Seq + Len

可以推断出:

  • SeqLen主要表达的是作为发送方当前的数据序号和长度
  • Ack主要表达的是作为接收方的接收到的数据序号和长度的和
  • TCP通信中,一个客户端/服务端既有发送的场景,也有接受的场景,因此Seq,和Ack都各自需要单独维护,Len则是实际的数据长度。

2.5. TCP头标志位——URG,ACK,PSH,RST,SYN,FIN

TCP头包含一系列的标识位(也称作控制位或标志位),它们用于控制和管理TCP连接的不同方面。每个标识位都占用TCP头部中的1个比特。

Wireshark不仅帮我们“翻译”了当前封包的状态,也把TCP头的所有状态位都做了提示。

Untitled

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

2.6. TCP连接建立——三次握手

包号94~96行则为TCP的“三次握手”行为,发生在TCP连接建立之初:

Untitled

“三次握手”主要分为3步:

  1. 客户端 → 服务端:【SYN】申请建立连接,声明初始Seq
  2. 服务端 → 客户端:【SYN,ACK】收到连接请求,声明初始Seq,声明Ack=客户端声明的初始Seq + 1
  3. 客户端 → 服务端:【ACK】收到确认请求,声明Ack=服务端初始Seq + 1

2.7. TCP连接释放——四次挥手

包号104~107行则为TCP的“四次挥手”行为,发生在TCP连接需要中断,释放连接时:

Untitled

**“四次挥手”**主要分为4步,发起方可能是客户端,也可能是服务端:

  1. 发起方发起释放连接请求:【FIN,ACK】,声明SeqAck
  2. 接受方返回确认收到:【ACK】,声明Ack=第1.步中发起方的Seq + 1
  3. 接收方发起释放连接请求:【FIN,ACK】,声明SeqAck(与上一步一样)
  4. 发起方返回确认收到:【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的数值:

Untitled

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

窗口大小在TCP协议设计之初只留了2byte,这个可以在Wireshark中看到:

Untitled

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

Untitled

最终窗口大小计算公式 = Window的数值 8442 * 2的window scale次方

2.9. 动态调整TCP窗口——从慢启动到阻塞避免

在上一部分大包拆分中,可以看到TCP窗口是会动态调整的,这是有一个具体的调整策略的。

  1. 连接刚建立,发送方对网络情况一无所知,需要定一个初始值,可以是几个MSS大小。
  2. 连接初期,由于发生拥塞概率很低,如果发出去的包都得到确认,可以尝试增大阻塞窗口,RFC建议是每收到n个确认,阻塞窗口就增大n个MSS,这个过程需要慢慢增长,称为慢启动过程
  3. 持续一段时间后,窗口大小达到一个较大的值,发生拥塞的概率变大,不能继续使用慢启动的算法,需要再缓慢一点,RFC建议每个往返时间增加1个MSS,这个过程称为拥塞避免。

Untitled

2.10. 丢包问题——RTO与快速重传

TCP连接过程中有可能出现丢包的情况。

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

Untitled

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

Untitled

RTO的过程对性能影响是比较大的:

  1. RTO阶段等待重传不能传数据,浪费处理时间
  2. RTO之后的TCP窗口急剧减小,传输比之前慢

与RTO不同,如果拥塞很轻微,发生部分丢包,发送方还是能接收到部分Ack包,Ack会有期望Seq号,通过这个期望Seq号,发送方会意识到发生包丢失,当发送方收到3个及以上Dup Ack(重复确认)时会立刻重传,这个过程称为快速重传

这里之所以需要凑齐3个及以上Dup Ack的原因是实际场景中包可能会乱序,Ack好像表现出一个缺失的包,但是这个包并没有丢失,而是由于乱序还在数据传输路上,可能很快就会传输过来,因此设置一个数量要求一定程度避免乱序导致快速重传

Untitled

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

Untitled

2.11. 减轻网络负担可能降低性能——延迟确认与Nagle算法

  • 延迟确认:如果收到一个包后暂时没什么数据要发给对方,那就延迟一段时间再确认;假设这段时间内恰好有数据要发出,则确认信息和数据可以在一个包里发。延迟确认减少了部分确认包,减轻了网络负担,但有时候会影响性能,带来传输数据延迟。
  • Nagle算法:在发出去的数据还没有被确认之前,如果有小数据生成,就把小数据收集起来凑满一个MSS或者等收到确认后再发送。

3. 参考资料

  • 林沛满 -《Wireshark网络分析就这么简单》
  • 刘超 ——《趣谈网络协议》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/362228.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

正则表达式 与文本三剑客(sed grep awk)

一&#xff0c;正则表达式 &#xff08;一&#xff09;正则表达式相关定义 1&#xff0c;正则表达式含义 REGEXP&#xff1a; Regular Expressions&#xff0c;由一类特殊字符及文本字符所编写的模式&#xff0c;其中有些字符&#xff08;元字符&#xff09;不表示字符字面意…

【GPU驱动开发】-LLVM和Clang环境部署

前言 不必害怕未知&#xff0c;无需恐惧犯错&#xff0c;做一个Creator&#xff01; 一、下载LLVM源码 官网下载源码 https://github.com/llvm/llvm-project/releases/ 包含所有llvm版本的下载内容 win源码传到ubuntu 首先将虚拟机关机&#xff0c;在虚拟机设置中&#xff…

微服务—Docker

目录 初识Docker Docker与虚拟机的区别 镜像与容器 Docker架构 常见Docker命令 镜像命令 容器命令 数据卷挂载 直接挂载 初识Docker 在项目部署的过程中&#xff0c;如果出现大型项目组件较多&#xff0c;运行环境也较为复杂的情况&#xff0c;部署时会碰到一些问题&…

stm32--simulink开发之--timer的学习,硬件输入中断,触发事件

总体的参考链接是&#xff1a; https://ww2.mathworks.cn/help/ecoder/stmicroelectronicsstm32f4discovery/ref/timer.html 输入&#xff1a; 1&#xff0c;配置项&#xff1a;Enable frequency input 缩写&#xff1a;freq conunt 说明&#xff1a;“freq count — Frequency…

[Mac游戏]割绳子3 Cut the Rope 3 v1.3.0 for Mac 苹果电脑游戏

你准备好和Am Nom和迷人的Kus Nom一起去未开发的土地了吗&#xff1f;这场激动人心的冒险从一张旧地图和诱人的伟大发现开始。然后你们三个将带着狡猾的谜题去不可思议的地方旅行&#xff01;解决所有问题&#xff0c;找到Nyammi的新物种&#xff0c;并成为伟大的先驱。 对于那…

收集子域名信息(三):Layer 工具(附链接)

一、介绍 Layer 子域名挖掘机是一款域名查询工具&#xff0c;可提供网站子域名查询服务&#xff1b;拥有简洁的界面、简单的操作模式&#xff0c;支持服务接口、暴力搜索、同服挖掘三种模式&#xff0c;支持打开网站、复制域名、复制 IP、复制 CDN、导出域名、导出 IP、导出域…

【SpringBoot系列】自动装配的魅力:Spring Boot vs 传统Spring

IT行业有哪些证书含金量高? 文章目录 IT行业有哪些证书含金量高?强烈推荐前言区别项目配置&#xff1a;依赖管理&#xff1a;内嵌服务器&#xff1a;开发体验&#xff1a; 实例Spring项目示例&#xff1a;Spring Boot项目示例&#xff1a; 总结强烈推荐专栏集锦写在最后 强烈…

SpringBoot后端接收Axios上传的文件

很多时候&#xff0c;我们项目开发的过程中&#xff0c;难免会遇到文件上传的需求 对于SpringBoot项目&#xff0c;我们该如何编写一个文件上传的接口呢&#xff1f; 这里我用的是阿里云OSS云服务器来作为上传文件的存储仓库&#xff0c;比起存储在电脑本地&#xff0c;云服务…

Histone H3K27ac Antibody, SNAP-ChIP® Certified

EpiCypher是一家为表观遗传学和染色质生物学研究提供高质量试剂和工具的专业制造商。EpiCypher&#xff08;国内代理商欣博盛生物&#xff09;推出的ChIP级别的Histone H3K27ac Antibody符合EpiCypher的“SNAP-ChIP Certified”标准&#xff0c;用于ChIP实验中的特异性和有效靶…

数据标准经验分享

给客户做数据类项目&#xff0c;在做数据标准时的经验分享 1. 收集本项目的数据范围内的数据 2. 整理本数据范围内的所有元数据 3. 观察该公司所有元数据的表命名、字段命名规律 4. 根据行业经验&#xff0c; 国标、行标&#xff0c; 也根据元数据范围&#xff0c;制定本公司…

elementUI实现selecttree自定义下拉框树形组件支持多选和搜索

elementUI实现selecttree自定义下拉框树形组件支持多选和搜索 效果图定义子组件父组件应用 效果图 定义子组件 主要结合el-select和el-tree两个组件改造的。 <template><div class"selectTree"><el-select filterable :filter-method"filterMe…

【HarmonyOS应用开发】ArkUI 开发框架-进阶篇-Video组件的使用(十)

一、Video组件的使用 1、概述 在手机、平板或是智慧屏这些终端设备上&#xff0c;媒体功能可以算作是我们最常用的场景之一。无论是实现音频的播放、录制、采集&#xff0c;还是视频的播放、切换、循环&#xff0c;亦或是相机的预览、拍照等功能&#xff0c;媒体组件都是必不可…

分割头篇 | 原创自研 | YOLOv8 更换 SEResNeXtBottleneck 头 | 附详细结构图

左图:ResNet 的一个模块。右图:复杂度大致相同的 ResNeXt 模块,基数(cardinality)为32。图中的一层表示为(输入通道数,滤波器大小,输出通道数)。 1. 思路 ResNeXt是微软研究院在2017年发表的成果。它的设计灵感来自于经典的ResNet模型,但ResNeXt有个特别之处:它采用…

EDI报文到Excel转换方案详解

EDI目前已广泛应用于电子、物流、汽车、零售等行业。 越来越多的交易伙伴要求建立EDI连接&#xff0c;通过EDI来对接上下游交易伙伴&#xff0c;收发业务单据。 当我们与新的交易伙伴建立EDI连接时&#xff0c;有多种实施方案可供选择&#xff0c;如果您的单据量较少&#xf…

游戏APP用户行为统计分析

文章目录 1.游戏业务数据分析如图所示的用户行为数据2.数据预处理2.1加载包2.2读取数据2.3查看安装信息2.4查看注册信息2.5查看安装信息表中的最大值&#xff0c;最小值等基本信息。2.6查看注册信息表中的最大值&#xff0c;最小值等基本信息。 3.数据分析3.1数据统一3.2安装信…

ADSelfService Plus 推出离线多因素身份验证以提升远程工作安全性

采用先进验证方法&#xff0c;确保在任何时间、地点或连接问题下对业务数据的合法访问即使远程用户未连接到身份验证服务器或互联网&#xff0c;也可通过MFA安全认证。 MFA 得克萨斯州德尔瓦雷 — 2023年5月3日 — Zoho Corporation 旗下的企业IT管理部门ManageEngine今日宣布…

做好测试用例的分析 ? 是做好软件测试的必要步骤。

目录 1.测试用例的分析指标 2.可能原因的论证 3.确定原因的解决方案 测试用例作为测试人员最重要的输出物之一 &#xff0c;它的作用不仅仅是能保证需求覆盖 &#xff0c;提高测试覆盖率等 。通过对执行后的测试用例分析 &#xff0c;你也可以发现更多在编写上&#xff0c;执…

【百度Apollo】本地调试仿真:加速自动驾驶系统开发的利器

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下…

05 - 什么是路由协议

1 路由协议 路由协议&#xff08;英语&#xff1a;Routing protocol&#xff09;&#xff1a; 是一种指定数据包转送方式的网上协议。Internet网络的主要节点设备是路由器&#xff0c;路由器通过路由表来转发接收到的数据。 路由协议&#xff0c;根据转发策略进行分类&#xff…

C/C++ - 类的多态机制

目录 多态概念 多态定义 多态的触发机制 虚函数 虚函数表 虚析构函 虚析构函数声明 虚析构函数的作用 纯虚函数 纯虚函数的声明 纯虚函数的作用 抽象类 多态原理 虚函数表 & 虚函数指针 继承机制下的虚函数表 动态绑定 多态概念 狗狗发出的声音为 -> 旺…