当前位置: 首页 > backend >正文

计算机网络:(十四)传输层(下)详细讲解TCP报文段的首部格式,TCP 可靠传输的实现与TCP 的流量控制

计算机网络:(十四)传输层(下)详细讲解TCP报文段的首部格式,TCP 可靠传输的实现与TCP 的流量控制

  • 前言
  • 一、TCP 报文段的首部格式
    • 1. 回顾 :TCP 报文段是什么?
    • 2. 首部格式:
    • 3. 层级关系:包裹怎么发送?
  • 二、TCP 可靠传输的实现
    • 1. 为什么有滑动窗口?
    • 2. 窗口是“字节”做的
      • 2.1 发送方和接收方各有一个“窗口”
      • 2.2 窗口里的序号怎么分?
    • 3. 窗口动态适应传输情况
      • 场景1:发送方发了一部分数据后
      • 场景2:收到回复后,窗口往前滑
  • 三、缓存
    • 1. 发送缓存
    • 2. 接收缓存
    • 3. 几个重要提醒
    • 4. 接收方啥时候回复“收到了”?
    • 5. 超时重传:丢了就再发一次
        • (1)超时时间不能乱设
        • (2)用“自适应算法”算时间
    • 6. 选择确认(SACK):只重传丢的部分
  • 三、TCP 的流量控制
    • 1. 什么是流量控制?为啥需要它?
    • 2. 滑动窗口
    • 3. 零窗口怎么办?
    • 4. TCP怎么发报文更高效?
    • 5. “糊涂窗口综合症”
        • 举个夸张的例子:
        • 怎么解决接收方的“糊涂”?


前言

  • 在前序博客中,我们已对用户数据报协议(UDP)和传输控制协议(TCP)进行了概述性介绍。​
  • 接下来,我们将深入剖析 TCP 的核心知识点,具体包括:TCP 报文段的首部格式、TCP 可靠传输的实现机制,以及 TCP 的流量控制方法
    在这里插入图片描述

我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的计算机网络专栏,欢迎来阅读
https://blog.csdn.net/2402_83322742/category_12909527.html


一、TCP 报文段的首部格式

在这里插入图片描述

1. 回顾 :TCP 报文段是什么?

TCP 是负责“可靠送货”的运输层协议,它发送的数据单元叫 TCP 报文段,就像一个“快递包裹”:

  • 首部:相当于“面单”,写着传输规则和控制信息(必须读!)。
  • 数据部分:相当于“包裹里的东西”,是真正要传的内容(比如网页、消息)。

2. 首部格式:

TCP 首部的 前 20 字节是固定的(必须填的项),后面还能加“可选备注”(选项字段),所以首部总长度是 4n 字节(n 是整数,保证长度是 4 的倍数,方便计算机处理)。

字段名占多少位通俗理解
源端口、目的端口各 16 位(2 字节)像“发件人电话”和“收件人电话”,区分是哪个应用程序在收发数据(比如浏览器用 80 端口)。
序号32 位给数据编号(比如“这是第 100 个包裹”),保证接收方按顺序组装,不乱套。
确认号32 位告诉对方“我收到你到编号 150 为止的包裹了”,确认数据没丢。
数据偏移4 位表示“首部占多少个 4 字节”(比如值为 5 → 5×4=20 字节,对应固定首部)。
保留位6 位留着备用(暂时没用,别管它)。
控制位(URG、ACK、PSH、RST、SYN、FIN)各 1 位像 6 个“开关”,控制连接和传输:
- SYN:建立连接时“打招呼”;
- ACK:确认号生效(开了才表示确认);
- FIN:说“我没数据发了,准备断开”;
- 其他:紧急数据、重置连接、催促处理等。
窗口16 位告诉对方“我还能收多少数据”(比如“我最多还能装 1000 字节”),避免对方发太多把我撑爆(流量控制)。
检验和16 位像“防伪码”,检查数据和首部有没有传错。
紧急指针16 位和 URG 配合,指出“紧急数据在哪”(比如“包裹里第 50 字节是紧急内容,先处理!”)。
选项 + 填充可变长度选项:可选功能(比如协商“一次最多发多少数据”);
填充:凑数,让首部长度是 4 的倍数(因为数据偏移按 4 字节算)。

3. 层级关系:包裹怎么发送?

TCP 报文段(首部 + 数据)会被 装进 IP 数据报 里:

  • TCP 报文段 → 成为 IP 数据报的 数据部分
  • 再给它加一个 IP 首部(像物流面单,写着源 IP、目的 IP 等),最终变成“IP 数据报”发送。

就像:TCP 小包裹 → 套上 IP 物流壳 → 全网运输

二、TCP 可靠传输的实现

1. 为什么有滑动窗口?

TCP发送数据时,不是发一个等一个回复(那样太慢了),而是用“滑动窗口”一次发一堆,同时保证不丢数据。

就像货车拉货,一次能拉一车厢(窗口),不用每送一件就回来汇报。

在这里插入图片描述

2. 窗口是“字节”做的

TCP里的“窗口”不是物理窗口,而是以字节为单位的序号范围。比如发送方要发1-100号字节,窗口可能允许先发送1-20号,这就是“窗口大小为20”。

2.1 发送方和接收方各有一个“窗口”

  • 发送窗口:发送方能连续发送的字节范围(没收到回复也能发)。比如窗口是31-50,就可以一次发31到50号字节,不用等前面的确认。
  • 接收窗口:接收方只接收落在这个范围内的字节。比如窗口是31-50,收到32号字节会暂存,但收到51号就拒收。

2.2 窗口里的序号怎么分?

拿例子来说(假设接收方告诉发送方“窗口大小20”):

  • 已发且收到确认的:26-30号(这些没问题,不用管了)。
  • 发送窗口:31-50号(允许发送的范围,蓝色区域)。
  • 不能发的:51号及以后(红色叉叉,超范围了)。

窗口的“边”可以动:前面的边(后沿)能往前移(比如确认了31号,后沿就从31移到32);后面的边(前沿)也能往前移(窗口变大时),但不能往后缩(不然会乱序)。
在这里插入图片描述

3. 窗口动态适应传输情况

窗口不是固定的,会随着数据发送、确认不断往前“滑”,就像传送带一样,前面的处理完了,后面的跟上。

场景1:发送方发了一部分数据后

在这里插入图片描述

假设发送方从31号开始发了11个字节(31-41号):

  • 发送方这边:

    • 已发且确认:26-30号(老样子)。
    • 已发但没确认:31-41号(红色,等着回复)。
    • 还能发但没发:42-50号(粉色,窗口里剩下的位置)。
  • 接收方这边:
    在这里插入图片描述

    • 已确认并交给应用程序:26-30号。
    • 收到了但没按顺序:比如32-33号(棕色,先暂存着,等31号到了一起处理)。
    • 还能接收:31-50号(窗口没变,等着31号和剩下的)。

场景2:收到回复后,窗口往前滑

在这里插入图片描述

当接收方确认“31-33号收到了”,窗口就会往前挪:

  • 发送方窗口变成34-52号(前沿往前移了,能发更多新数据)。
  • 接收方窗口也变成34-53号(确认过的就移出窗口,腾出位置给新数据)。

小公式帮你理解窗口
在这里插入图片描述

  • 发送窗口大小 = 最后能发的序号 - 已确认的最后序号(比如50-30=20)。
  • 已发未确认 = 已发的最后序号 - 已确认的最后序号(比如41-30=11)。
  • 还能发 = 发送窗口大小 - 已发未确认(比如20-11=9,对应42-50号)。

三、缓存

发送方和接收方都有“缓存”,就像快递站的暂存区,数据在发送/接收过程中先放这儿

1. 发送缓存

在这里插入图片描述

  • 应用程序把要发的字节流先放进这里。
  • 发送窗口只是缓存里的一小部分(比如缓存有30-60号,窗口只包含31-50号)。
  • 里面分:已发的(粉色)、窗口内没发的(蓝色)、还没进窗口的(灰色)。

2. 接收缓存

在这里插入图片描述

  • 接收方收到的数据先放这儿,等按顺序排好后再交给应用程序。
  • 里面分:已收到的(粉色)、乱序暂存的(比如32-33号,棕色)、等着接收的(窗口内,蓝色)。

3. 几个重要提醒

  1. 发送窗口和接收窗口不一定一样大:接收方告诉发送方“我窗口20”,但发送方收到这个消息时,接收方的窗口可能已经变了(有延迟),所以两者可能暂时不等。
  2. 乱序数据怎么处理?:收到32号但没收到31号时,不会直接扔掉,而是暂存在接收缓存里,等31号到了再一起按顺序交给应用程序。
  3. 累积确认:接收方不用收到一个就回复一次,比如收到31-33号,直接回复“我收到33号了,下一个等34号”,一次确认多个,省流量。

4. 接收方啥时候回复“收到了”?

  • 适时发:别等太久(不然发送方以为丢了,会重发,浪费资源),也别收到就发(太频繁),一般等一小会儿,可能顺便把自己要发的数据一起带过去(叫“捎带确认”)。
  • 但“捎带确认”不常见:大部分时候只有一方发数据(比如你下载文件时,主要是服务器发,你只发确认),所以多数情况还是单独发确认。

5. 超时重传:丢了就再发一次

万一数据丢了怎么办?TCP会“超时重传”:发一个包就设个计时器,超过时间没收到回复,就再发一次。但“超时时间”设多久是个大学问!

(1)超时时间不能乱设
  • 设太短:还没等回复回来就重发,导致网络里一堆重复包,堵车。
  • 设太长:等半天发现丢了才重发,效率太低。
(2)用“自适应算法”算时间

TCP会记录一个包从发出去到收到回复的时间(叫RTT,往返时间),然后用这个算超时时间(RTO)。

  • 平滑RTT(RTTs):不是直接用单次RTT,而是加权平均(比如新测的RTT占1/8,旧的占7/8),避免忽快忽慢的波动。
  • 超时时间(RTO):比平滑RTT稍大一点,还要考虑RTT的波动(比如有时候快有时候慢),公式是“RTO = RTTs + 4×波动值”,这样更靠谱。

6. 选择确认(SACK):只重传丢的部分

如果收到的字节是乱序的(比如收到1-100、150-300,缺了101-149),难道要把150-300号再重发一次吗?不用!

  • SACK(选择确认)就是解决这个问题的:接收方告诉发送方“我收到1-100和150-300了,就缺101-149”,发送方只重传缺少的部分,不用重发已经收到的,效率大大提高。

三、TCP 的流量控制

1. 什么是流量控制?为啥需要它?

想象一个场景:你(发送方)给朋友(接收方)发文件,你网速超快,一秒发100M;但朋友的电脑内存小,一秒只能处理10M。如果不控制,朋友的电脑很快就会被“塞满”,后面的数据就会丢失。

流量控制就是解决这个问题的:让发送方的发送速率“匹配”接收方的处理能力,确保接收方来得及接收和处理数据

2. 滑动窗口

TCP用之前讲过的“滑动窗口”来实现流量控制,核心是接收方通过“接收窗口(rwnd)”告诉发送方:“我现在还能收这么多数据,你别超了”

举个例子:一步步看流量控制怎么工作

  • 假设:A(发送方)给B(接收方)发数据,每次最多发100字节(MSS=100);一开始B告诉A:“我现在能收400字节(rwnd=400)

在这里插入图片描述

  1. A先发1-100字节 → 还能发300字节(400-100=300)。
  2. A再发101-200字节 → 还能发200字节(300-100=200)。
  3. A接着发201-300字节,但这包丢了(B没收到)。
  4. B收到1-200字节,回复A:“我收到200字节了,接下来等201字节,现在还能收300字节(rwnd=300)” → 允许A发201-500字节(201+300-1=500)。
  5. A没收到201-300的确认,但可发301-400字节(在201-500范围内)→ 还能发100字节。
  6. A再发401-500字节 → 此时201-500中,301-500已发,但201-300丢了,暂时不能发新数据。
  7. A等了很久没收到201-300的确认,超时重传201-300字节。
  8. B终于收到201-500全部数据,回复:“收到500字节了,现在还能收100字节(rwnd=100)” → 允许发501-600字节。
  9. A发501-600字节 → 暂时不能再发了。
  10. B处理完501-600,回复:“收到600字节了,现在我缓存满了,暂时收不了(rwnd=0)”。

3. 零窗口怎么办?

在这里插入图片描述

如果接收方回复“rwnd=0”(我现在一点都收不了),发送方就会停发数据。但万一接收方后来有空了,却没机会告诉发送方,双方就会一直“等”对方——这就是“死锁”

持续计时器就是解决这个问题的:

  • 发送方收到“rwnd=0”时,启动一个计时器。
  • 计时器到期后,发一个“1字节的探测包”给接收方。
  • 接收方收到后,会回复现在的窗口大小:如果还是0,发送方就重置计时器再等;如果窗口变大了,就可以继续发数据,打破死锁。

4. TCP怎么发报文更高效?

流量控制是为了“不堵车”,但光不堵还不够,还得高效。TCP发报文的时机有三种:

  1. 攒够一波再发:缓存里的数据凑够“最大报文段长度(MSS)”时,打包发送(比如MSS=100,凑够100字节就发)。
  2. 应用催着发:如果应用程序急着要发送(比如点了“发送”按钮),会主动触发发送。
  3. 到点了就发:如果一直凑不够MSS,发送方的计时器到期后,不管多少数据都会发出去(避免一直拖着)。

5. “糊涂窗口综合症”

有时候,TCP会犯“糊涂”,每次只发一点点数据,导致效率极低,这就是“糊涂窗口综合症”。

举个夸张的例子:
  • 发送1字节数据,TCP首部要20字节(固定开销),所以TCP段一共21字节。
  • 加上IP首部20字节,整个数据包41字节。
  • 真正有用的数据只有1字节,效率=1/41≈2.4%——几乎全在传“包装”,太浪费了!
怎么解决接收方的“糊涂”?

接收方是“糊涂”的源头之一:如果接收方一有空位就急着告诉发送方“我能收1字节了”,发送方就会发1字节,导致低效。

解决办法:接收方别着急,等缓存满足两个条件之一再通知发送方:

  1. 缓存能放下“最大报文段(MSS)”;
  2. 缓存的空闲空间达到一半(比如缓存总大小1000字节,至少有500字节空闲)。

这样接收方就不会频繁报“小窗口”,发送方也就不会发“小报文”了,效率自然就上去了。


以上就是本篇博客的全部内容,下一篇我们继续探讨计算机网络里面的知识。

我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的计算机网络专栏,欢迎来阅读
https://blog.csdn.net/2402_83322742/category_12909527.html

如果您觉得内容对您有帮助,欢迎点赞收藏,您的支持是我创作的最大动力!

在这里插入图片描述

http://www.xdnf.cn/news/17424.html

相关文章:

  • Mybatis和MybatisPlus的对比区分理解法
  • 基于 RabbitMQ 死信队列+TTL 实现延迟消息+延迟插件基本使用
  • 给AI装上“翻译聚光灯”:注意力机制的机器翻译革命
  • Docker 镜像常见标签(如 `标准`、`slim`、`alpine` 和 `noble`)详细对比
  • 编程基础之字符串——统计数字字符个数
  • TypeScript 中的as const是什么?
  • React:useEffect 与副作用
  • token危机解决?扩散模型数据潜力3倍于自回归,重训480次性能仍攀升
  • 浏览器CEFSharp88+X86+win7 之多页面展示(四)
  • LLaMA-Adapter Efficient Fine-tuning of Language Models with Zero-init Attention
  • Redis - 使用 Redis HyperLogLog 进行高效基数统计
  • Spring Boot与WebSocket构建物联网实时通信系统
  • 基于Spring Boot和WebSocket的实时聊天系统
  • go语言运算符
  • 遇到前端导出 Excel 文件出现乱码或文件损坏的问题
  • Linux 管道命令及相关命令练习与 Shell 编程、Tomcat 安装
  • 基于Ubuntu20.04的环境,编译QT5.15.17源码
  • Lua语言元表、协同程序
  • JavaWeb(苍穹外卖)--学习笔记17(Apache Echarts)
  • LightGBM 与 GBDT 在机器学习中的性能与特点比较
  • Graph-R1:一种用于结构化多轮推理的智能图谱检索框架,并结合端到端强化学习
  • 【最后203篇系列】031 构建MCP尝试
  • Docker Compose 部署高可用 MongoDB 副本集集群(含 Keepalived + HAProxy 负载均衡)
  • 从零学习three.js官方文档(二)——图元
  • 去除Edge微软浏览器与Chrome谷歌浏览器顶部出现“此版本的Windows不再支持升级Windows 10”的烦人提示
  • JavaWeb(苍穹外卖)--学习笔记18(Apache POI)
  • 安全引导功能及ATF的启动过程(五)
  • 数据结构:栈和队列(Stack Queue)基本概念与应用
  • AI编程插件对比分析:CodeRider、GitHub Copilot及其他
  • 云服务器最新版MySQL 安装步骤