计算机网络:运输层 - TCP首部格式 连接的创建与释放
计算机网络:运输层 - TCP首部格式 & 连接的创建与释放
- TCP首部格式
- 源端口 目的端口
- 序号
- 确认号
- 数据偏移
- 保留
- 控制位
- 窗口
- 检验和
- 紧急指针
- TCP连接创建 - 三次握手
- TCP传输过程
- TCP连接释放 - 四次挥手
TCP首部格式
TCP
的首部如下:
首部的前20 byte
是固定的,后面的选项
字段可变。
源端口 目的端口
源端口
和目的端口
各占2 byte
,即填入通信的两个进程使用的端口号。
序号
占4 byte
,范围是 [ 0 , 2 32 − 1 ] {\red{[0, 2^{32} - 1]}} [0,232−1] ,TCP
是面向字节流的,在TCP
中传输的每一个字节都要按顺序进行编号。整个传输过程中,第一个字节的值是任意的,由发送方随机设定,后续所有字节都由第一个字节的编号以及偏移量得出。比如整个TCP
连接中,第一个字节编号为x
,那么第201
个字节的编号就是x + 201
。
如果某个字节在编号时,超出了 2 32 − 1 2^{32} - 1 232−1 ,此时从0
开始重新计数。
确认号
占4 byte
,含义是:期望收到对方下一个报文段的第一个字节的序号。
例如,主机B
收到了来自A
的编号为501
的数据报,数据报长度为200
。这说明主机B
收到了编号为501 - 700
字节的数据。那么主机B
接下来就期望收到701
开始的数据,此时确认号就设为701
。
若确认号为 n,说明 n - 1 及之前的所有数据都已经收到了
数据偏移
占4 bit
,其含义为:报文起始处
到数据起始处
的距离,简单理解就是整个首部的长度。
由于TCP
带有填充字段,所以长度是不确定的,需要该字段来指明长度。另外的,由于只占该字段只占4 bit
,能表示的范围是 [ 0 , 2 4 − 1 ] {\red{[0, 2^{4} - 1]}} [0,24−1],也就是[0, 15]
,而数据偏移
字段以4 byte
为单位。所以整个首部的长度最长为60 byte
,进而说明选项字段
的长度不超过40 byte
。
保留
占6 bit
,目前没有用,使用时设为全0
。
控制位
接着就是连续的留个控制位
。
紧急 URG:当URG = 1
,表明紧急指针
字段有效,告诉系统此报文有紧急数据,需要尽快传送,此时该报文就无需排队,直接插入到队列的首部立马发送出去。
确认 ACK:当ACK = 1
时,确认号
字段才有效。TCP
规定:在连接建立后所有的传送报文段,ACK
必须置为1
。
推送 PSH:发送该报文后,如果希望尽快收到对方的回应,就可以PSH = 1
。接受方收到该报文后,会立刻把该报文提交给应用进程,而不是等到接收缓存满了才提交。
复位 RST:当RST = 1
,表示TCP
连接出现重大差错,必须释放连接。也可以用来拒绝一个连接或报文段。
同步 SYN:用于建立连接
- 当
SYN = 1
并且ACK = 0
,表明这是一个连接请求报文
,(ACK = 0
的情况,一般来说整个TCP
连接只有此处ACK = 0
) - 当
SYN = 1
并且ACK = 1
,表明这是一个连接同意报文
终止 FIN:用于释放一个连接,当FIN = 1
,表明这是一个释放连接的报文
窗口
占2 byte
,用于指明自己的接收窗口,对方收到该报文后,读取窗口
字段,就知道自己接下来可以发送多少数据了。
检验和
占2 byte
,检验范围包括首部
和数据
两部分,与UDP
一样,在计算检验和时,要加上伪首部
。
如图:
只有计算检验和
时才会存在伪首部
,实际上其不存在,TCP 数据报
中只有首部
和数据
。
紧急指针
占2 byte
,仅在URG = 1
时才有效。当URG = 1
,说明这是一个紧急的报文,此时要立刻发出去,整个数据报会插队到其他数据报的前面。那么计算机怎么知道这个紧急报文的长度是多少?
此时就需要紧急指针
字段,其指明了本报文中紧急数据的字节数,当把所有紧急数据处理完后,就要恢复正常状态,把之前的数据发送出去。而什么时候紧急数据发送完,就是依靠紧急指针
字段指明的紧急数据的字节数。
讲解完报文的格式后,我们来讲解TCP
连接的创建与释放。后续会用到一些标识符,接下来我解释一下每个标识符对应数据报首部的哪一个字段:
seq
:对应首部中的序号
字段,指明希望收到的下一个数据的序号是什么ack
:对应首部中的确认号
字段,表明xxx之前的所有数据都已经收到了ACK
:对应首部中的确认位
字段,表明确认号
有效SYN
:对应首部中的同步位
字段,用于创建TCP
连接FIN
:对应首部中的终止位
字段,用于终止TCP
连接
TCP连接创建 - 三次握手
假设现有一台客户
主机A
,一台服务器
主机B
,现在A
申请向B
发起TCP连接
。
处于创建连接的过程中,SYN
就起作用了,如图:
首先令SYN = 1
,表明当前正在创建连接,创建连接的报文分两种情况:
- 当
SYN = 1
并且ACK = 0
,表明这是一个连接请求报文
,(ACK = 0
的第一种情况) - 当
SYN = 1
并且ACK = 1
,表明这是一个连接同意报文
当前A
正在发起连接的请求,所以此时ACK = 0
,注意:后续只要不标明的位,都是0。
而发送数据是要对每个字节进行编号的,第一个字节的编号由主机随机生成,此时seq = x
表明:第一个字节的编号为x
。
当A
发起请求后,此时B
就要同意这个连接:
同意连接是SYN = 1
,ACK = 1
,表明当前报文用于同意一个连接。此时主机B
也要生成第一个字节的编码,也就是seq = y
。
B
在回应时,还有一个字段ack = x + 1
,ack
表示:我希望收到的下一个数据的编号。
比如说某一次报文发送时,第一个字节的编号为666
,总数据长度为200 byte
,那么接收方就收到了[666, 865]
的所有数据,此时回应报文为ack = 866
表明下一个数据的编号为866
。
那么目前来说刚刚TCP请求报文
的编号为seq = x
,现在我回应ack = x + 1
,是不是可以理解为:整个TCP请求报文
只携带一个字节的数据呢?
TPC
规定:SYN = 1
的报文不允许携带数据,但是消耗掉一个seq
其实SYN = 1
的报文不携带数据部分,但是TCP
强制规定了其要消耗掉一个seq
,因此刚刚序号x
视为被消耗了,下一个字节的序号为x + 1
。
当A
收到B
的确认后,此时A
也要再给B
做一次确认:
这个确认,是对第二个报文的确认,此时SYN = 0
,因为其既不是连接请求
,也不是连接同意
。ACK = 1
表明ack
字段有效。seq = x + 1
,因为第一个报文seq = x
,并且SYN = 1
要消耗掉一个需要,此时就用下一个序号x + 1
。
ack = y + 1
是因为,刚刚B
发送的报文seq = y
,而SYN = 1
要消耗掉一个序号,此时希望收到的下一个序号为y + 1
。
接下来考虑一个问题:为什么需要三次报文交换才能建立连接?明明A
发送一个请求,B
发送一个同意,就表明双方都准备建立连接了,为什么不直接开始传输数据,而是还要第三次确认?
这是因为在B
发送第二个同意报文后,A
可能还没准备好接收数据。比如说B
发送的同意报文丢失了,此时A
还在等待B
的同意,而B
以为A
已经可以发送数据了。结果B
发送了一段数据后,A
根本不接收,因为A
在等B
的同意。此时就是A
没有准备好。
因此A
要发送第三个报文,来表明自己已经准备好了,对面可以开始发送数据了。
另外的,第三个报文是可以携带数据的,此时A
发送第三个报文时,表明连接建立完毕了,于是A
就顺带可以把一部分数据先通过该报文传输过去!
对于
FIN = 0
,SYN = 0
且ACK = 1
的报文,可以携带数据,携带多少数据就消耗多少序号,如果不携带数据,就不消耗序号
现在连接已经创建完毕,就可以正常数据传输了!
TCP传输过程
很多地方都只讲了连接创建与释放的过程,反而没有说明传输的过程。其实这个过程也很重要,本博客再简单讲解一下传输的过程。
如图所示:
现在TCP
连接建立时,第三个报文携带了100
个数据(data用于说明这个报文携带了多少数据)。
随后A
又紧接着发送了300
个数据:
此时seq = x + 101
,这是因为刚刚的第三个报文携带了100 byte
的数据,其中第一个字节的编号为x + 1
,说明我已经把[x + 1, x + 100]
的数据发出去了,接下来的300
字节,第一个编号就是x + 101
了。
而ack = y + 1
,这是因为上一次收到B
的报文是SYN = 1
,ACK = 1
的连接同意报文,序号为y
,消耗掉一个序号后变为y + 1
,即下一个希望收到的编号为y + 1
。
随后B
发送了一个长度为200 byte
的报文:
此时seq = y + 1
,这是因为上一次B
发送的报文是seq = y
,而SYN = 1
消耗掉一个序号,这次第一个字节使用的序号为y + 1
。ack = x + 401
表明[x, x + 400]
的所有数据都收到了,下一个希望收到的序号是x + 401
,
随后A
再发送一个100 byte
的报文:
这时seq = x + 401
,因为之前发送了[x, x + 400]
的数据,下一个字节编号为x + 401
。ack = y + 201
表明[y, y + 200]
的数据都受到了。
以此类推,直到连接释放。
TCP连接释放 - 四次挥手
当TCP
连接传输数据完毕,此时就可以释放连接了。
TCP
连接释放可以由任意一方发起,假设现在A
发起释放连接:
首先要把FIN = 1
,表明A
发起了一个释放连接的请求。而seq = u
,表明当前的报文编号为u
,也说明之前A
传输的最后一个字节编号为u - 1
。ack = v
,表明A
收到的来自B
的最后一个字节是u
。
A
发起释放连接的请求,只说明A
要传送的数据已经完毕了,可以释放连接了。但是B
可能还有没有传送完的数据:
首先B
发送一个ACK
报文,表明自己已经收到了刚刚FIN = 1
的报文。
TCP
规定:FIN = 1
的报文,就算不携带数据也要消耗一个序号
A
发送的连接释放报文中,FIN = 1
并且不携带数据,那么也要消耗掉一个序号。因此B
希望收到的下一个序号是u + 1
。
如果B
收到该报文,那么ack = u + 1
,否则ack = u
,这样发送方就可以根据下一个报文得知B
有没有收到连接释放的请求包围了。
随后B
可以继续发送自己之前没发完的数据,这期间B
发送的报文FIN = 0
,表明B
还有数据要发,没这么快终止连接。
剩下B
发送的所有报文中ack = u + 1
,因为刚刚A
发送了一个FIN = 1
的报文。
而seq = v
,表明自己现在发送的数据中,第一个字节序号为v
。
当B
传输完自己的所有数据后,在发送释放连接的同意报文:
FIN = 1
表明这是一个连接释放的报文,在两个FIN = 1
的报文中间,B
还发了一些报文,导致序号一直增加,假设现在增加到了w
,那么seq = w
。
当B
发送完最后一个FIN = 1
的连接释放报文后,A
最后发送一个确认报文:
这是因为B
无法保证自己发出去的报文A
一定可以接收到,如果B
发送的FIN = 1
的报文丢失了,此时B
以为自己以为结束TCP
连接,而A
还在一直等待B
发出FIN = 1
的报文。所以要对这个FIN = 1
的报文最后做一次确认。
当这四个报文传输完毕,A
不能直接结束,而要等待2 MSL
:
MSL(Maximum Segment Lifetime,最大报文段生存时间)
:指的是一个TCP
报文在网络中存活的最长时间。
这是因为A
传送的最后一个确认报文也有可能丢失,B
如过发现A
没有回应,超时计时器结束就重传FIN = 1
的报文。而这个报文一定可以在2 * MSL
期间到达,所以如果A
在2MSL
期间没有收到B
的报文,说明最后一个报文B
收到了,可以释放连接了。
相关文章:

计算机网络:运输层 - TCP首部格式 连接的创建与释放
计算机网络:运输层 - TCP首部格式 & 连接的创建与释放 TCP首部格式源端口 目的端口序号确认号数据偏移保留控制位窗口检验和紧急指针 TCP连接创建 - 三次握手TCP传输过程TCP连接释放 - 四次挥手 TCP首部格式 TCP的首部如下: 首部的前20 byte是固定的…...

妈耶!被夸爆的零售数据分析方案在这里
在竞争激烈的零售市场中,数据分析已成为企业决胜的关键。今天,就为大家揭秘一份备受赞誉的零售数据分析方案——奥威BI零售数据分析方案,它围绕“人、货、场、供、财”五大主题,助力企业精准决策,实现业务增长。 一、人…...

AI探索:最佳落地应用场景
如果说今年的风口,那一定是 AI。不过AI像一把双刃剑,既有助益也有风险。我们将从IBM Watson的高飞与坠落,到Google Allo的黯然失色,探索AI应用中的教训。同时,瑞幸咖啡的成功故事展现了凭借策略得当的AI应用࿰…...

2024年最新机动车签字授权人考试题库。
31."简易瞬态工况法"所使用的五气分析仪的温度范图:分析系统及相关部件应在( )。 A.0-40℃ B.0-50℃ C.0-60℃ D.-10-40℃ 答案:A 32.稀释氧传感器环境空气量程检测时的读数值位于( )%vol范围之外时,应…...

软RAID
硬盘 连续空间 无法 扩容 lvm 非连续空间 可以动态扩容 raid 备份, 提高读写性能,不能扩容 raid 是磁盘的集合,按照排列组合的方法不 一,给 raid 去了不同的名字 raid0 raid1 raid5 raid10 什么是 RAID "RAID"…...

IDEA 学习之 启动“卡死”
目录 1. 断点问题2. IDEA 版本问题 1. 断点问题 部分断点涉及应用启动,会导致启动“卡死” 2. IDEA 版本问题 部分 IDEA 版本存在启动问题,本人之前遇到过(别人启动三分钟,我启动半个小时)。更换别的版本ÿ…...

豆瓣高分项目管理书籍推荐
📬豆瓣网站上有很多项目管理领域的书籍获得了较高的评分,以下是一些高分项目管理书籍的精选列表,发出来跟大家分享一下: 《项目管理知识体系指南(PMBOK指南)》 【内容简介】这本书是美国项目管理协会&…...

关于docker存储overlay2相关问题
报错如下: 报错原因:使用rm -rf 清理overlay2导致的,非正常清理。 正常清理命令如下: # 清理Docker的所有构建缓存 docker builder prune# 删除旧于24小时的所有构建缓存 docker builder prune --filter "until24h"#删…...

实现批量自动化电商数据采集|商品详情页面|店铺商品信息|订单详情数据
电商数据采集是指通过技术手段获取电商平台上的商品信息、店铺信息和订单信息等数据。这些数据可以用于市场分析、竞品分析、用户行为分析等。 商品详情页面是指电商平台上展示商品详细信息的页面,包括商品名称、价格、图片、描述、评价等信息。通过采集商品详情页…...

ES6(ECMAScript 6.0) 新特性
1 ES6 基本介绍 (1)ECMAScript 6.0(简称 ES6)是 JavaScript 语言的下一代标准, 2015 年 6 月发布。 (2)ES6 设计目标:达到 JavaScript 语言可以用来编写复杂的大型程序,成为企业级开发语言 &…...

性能工具之 JMeter 常用组件介绍(八)
文章目录 一、Jmeter命令行启动二、Jmeter脚本录制 本文主要介绍JMeter命令行启动和脚本录制功能 一、Jmeter命令行启动 Jmeter有两种运行: 一种是采用的界面模式(GUI)启动,会占用不少系统资源;另一种是命令行模式(n…...

分布式锁(Redission)
分布式锁: 使用场景: 通常对于一些使用率高的服务,我们会进行多次部署,可能会部署在不同的服务器上,但是他们获取和操作的数据仍然是同一份。为了保证服务的强一致性,我们需要对线程进行加锁,…...

【ARMv8/v9 GIC 系列 3 -- GIC 的 类型寄存器 GICD_TYPER】
文章目录 GIC 类型寄存器 GICD_TYPERESPI_Range, 位[31:27]RSS, 位[26]No1N, 位[25]A3V, 位[24]IDBits, 位[23:19]DVIS, 位[18]LPIs, 位[17]MBIS, 位[16]NUM_LPIs, 位[15:11]SecurityExtn, 位[10]NMI, 位[9]ESPI, 位[8]CPUNumber, 位[7:5]ITLinesNumber, 位[4:0]GIC 类型寄存器…...

MATLAB算法实战应用案例精讲-【数模应用】线性判别分析(附MATLAB、python和R语言代码实现)
目录 前言 算法原理 什么是判别分析 线性判别分析(LDA) 数学模型 二分类 多分类LDA 编辑 算法思想: 费歇(FISHER)判别思想 贝叶斯(BAYES)判别思想 LDA算法流程 LDA与PCA对比 SPSSPRO 1、作用 2、输入输出描述 3、案例示例 4、案例数据 5、案例操作 …...

打造智能家居:用ESP32轻松实现无线控制与环境监测
ESP32是一款集成了Wi-Fi和蓝牙功能的微控制器,广泛应用于物联网项目。它由Espressif Systems公司开发,具有强大的处理能力和丰富的外设接口。下面我们将详细介绍ESP32的基础功能和引脚功能,并通过具体的实例项目展示其应用。 主要功能 双核处…...

大型Web应用的模块化与组织实践:Flask Blueprints深入解析
目录 一、引言 二、Flask Blueprints概述 三、Flask Blueprints的使用 创建Blueprint对象 定义路由和视图函数 注册Blueprint 使用Blueprints组织代码 四、案例分析 创建模块目录结构 创建Blueprint对象 注册Blueprint 五、代码示例与最佳实践 1. 代码示例 …...
AI 智算产业发展现状和预测报告
一、引言 2023年,随着ChatGPT的横空出世,人工智能领域迎来了新的浪潮。我们正站在一个技术革命的前沿,迈入一个全新的智算时代。在这个时代,更高效的计算、更智能的推理、更敏捷的内容生成,正在重新定义着生产力和生产组织形态。2023年《数字中国建设整体布局规划》的发布…...

【软件工具】Xshell安装教程
1、安装软件:Xshell-5.0.1337p.exe,双击安装即可,可以选择安装到D盘; 2、在D盘安装完成后,将文件nslicense.dll拷贝到对应的安装目录下; 3、打开快捷方式即可打开应用软件。...
git如何切换到tag分支
项目场景: 当我们需要回退到某个tag分支。 问题描述 通过git命令 git checkout tag_name 执行这个命令后,会提示你当前处于一个“detached HEAD”的状态。 原因分析: 这是因为tag只是一个快照,是不能更改代码的。 解决方案&am…...

【启明智显产品介绍】Model3C工业级HMI芯片详解专题(三)通信接口
Model3C 是一款基于 RISC-V 的高性能、国产自主、工业级高清显示与智能控制 MCU, 集成了内置以太网控制器,配备2路CAN、4路UART、5组GPIO、2路SPI等多种通信接口,能够轻松与各种显示设备连接,实现快速数据传输和稳定通信,可以与各…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...