【零基础计网入门笔记 05】运输层
运输层可以比作城市快递分拣中心,把快递分给不同客户附近的快递点。 运输层只管电脑里的软件到对方电脑里的软件。一台电脑能同时开微信、浏览器、游戏,全靠运输层区分不同软件的数据。
本章重点速览:
- 运输层提供的服务
- UDP 协议
- TCP 协议 ※
一、运输层提供的服务
主要介绍运输层的通用基础功能。解决问题:卡车只送到城市,怎么精准分给城里不同住户附近的快递点? 一套通用规则(端口、收发区分、两种工作模式)。
1.1 运输层的介绍
-
定位:从通信和信息处理的角度看,运输层向它上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最低层。
-
核心能力:运输层位于网络层之上,它为运行在不同主机上的进程之间提供了逻辑通信,而网络层提供主机之间的逻辑通信。举例如下:
- 你手机(电脑 A)开微信给朋友手机(电脑 B)发消息:
- 网络层任务:数据包从你的手机 → 朋友手机(只送到设备,不知道给谁);
- 运输层任务:精准送到朋友手机里的微信软件,而不是浏览器、抖音。
- 你手机(电脑 A)开微信给朋友手机(电脑 B)发消息:
-
关键特新:即使网络层协议不可靠(网络层协议使分组丢失、混乱或重复),运输层同样能为应用程序提供可靠的服务, 保证软件收到完整正确数据。
1.2 运输层三大核心功能
- 端到端的通信
运输层提供应用进程之间的逻辑通信(软件 <-> 软件)。与网络层的区别是,网络层提供的是主机之间的逻辑通信。
- 复用和分用
- 复用(发送端):是指发送方不同的应用进程都可使用同一个运输层协议传送数据;
- 类比:家里三个人,同时寄快递,全部交给同一个分拣员统一打包运输。
- 举例:电脑同时开微信、浏览器、QQ,三个软件的数据全部交给运输层统一发出去。
- 分用(接收端):是指接收方的传输层在剥去报文的首部后能够把这些数据正确交付到目的应用进程。
- 类比:一堆包裹送到你家小区,分拣员看房间号,分别递给爸爸、妈妈、你。
- 举例:一堆数据发到你的电脑,运输层区分来源,微信的数据丢给微信,网页数据丢给浏览器。
- 运输层还要对收到的报文进行差错检测(首部和数据部分)
- 类比:分拣员收到包裹,先检查外包装有没有破损、缺东西,破损直接丢弃。
- 举例:运输层收到数据,校验数据有没有传输中损坏,坏的直接扔掉。
提供两种不同的传输协议,即面向连接的 TCP 和无连接的 UDP。
1.3 运输层的寻址与端口
1. 端口的作用
端口能够让应用层的各种应用进程将其数据通过端口向下交付给运输层,以及让运输层知道应当将其报文段中的数据向上通过端口交付给应用层相应的进程。
- IP 地址 = 你家小区完整地址(唯一定位一台电脑)
- 端口 = 小区里每户人家门牌号(唯一定位电脑里一个软件)
- 没有端口:数据包到了你小区,不知道送给谁,全部堆在门口
2. 端口号
服务器端使用的端口号。它又分为两类:
-
熟知端口号:数值为0~1023,把这些端口号指派给了 TCP/IP 最重要的一些应用程序,让所有的用户都知道,是固定公用门牌号,全网统一规定;
- 类比:相当于小区物业、快递站固定门牌,所有人都知道。
- 举例:网页浏览器访问网站永远走 80 号门;发邮件固定 25 号门;域名解析 DNS 固定 53 号门。
-
登记端口号:数值为1024~49151,它是供没有熟知端口号的应用程序使用的,小众软件专用门牌,需要官方登记避免冲突。
客户端使用的端口号为:
- 短暂端口号(也称临时端口):客户端(你的手机电脑)使用的端口号,数值为49152~65535。由于这类端口号仅在客户进程运行时才动态地选择。
- 举例:你打开浏览器刷网页,电脑随机分配一个临时端口,网页看完关闭,这个门牌号回收给别的软件用。
疑问:我打开浏览器刷网页,为什么是电脑随机分配一个临时端口,而不是直接用 80 端口?
解答:这个问题搞混【客户端】和【服务器】。熟知端口号是服务器的固定门牌号,而短暂临时端口是客户端(自己设备)上软件的临时编号,两者分工不同。完整的【访问百度网页】的例子如下:
百度那边的机器(网页服务器):它专门提供网页服务,官方规定网页服务固定用 80 熟知端口,相当于百度门店永久门牌号 80,所有人想来看网页,都去找 80 号门。
你的手机浏览器(客户端,主动发起请求的一方):你是访客,不能占用 80(80 是店铺专用),系统会随机给浏览器分配一个临时短暂端口,比如 51320。
完整通信流程:你的手机(临时端口 51320)→ 发送请求 → 百度服务器(固定端口 80)。百度收到请求后,回复数据时会标记「收件端口 51320」,你的手机收到数据,一看编号是 51320,就交给浏览器,不会错分给微信、游戏。
常见应用程序和对应端口号:
| 应用程序 | 英文全称 | 中文名称 | 端口 | 通俗用途 |
|---|---|---|---|---|
| FTP | File Transfer Protocol | 文件传输协议 | 21 | 电脑 / 服务器之间批量传大文件,早期网盘、网站上传文件都靠它 |
| TELNET | Teletype Network | 远程终端协议 | 23 | 远程操控另一台电脑 / 服务器,明文传输密码,现在基本淘汰不安全 |
| SMTP | Simple Mail Transfer Protocol | 简单邮件传输协议 | 25 | 专门用来发送邮件,比如你用 QQ 邮箱发消息给别人 |
| DNS | Domain Name System | 域名系统 | 53 | 上网第一步必用,把 baidu.com 翻译成服务器 IP 地址 |
| TFTP | Trivial File Transfer Protocol | 简易文件传输协议 | 69 | 极简版传文件,无加密无验证,仅局域网设备刷机、配置设备使用 |
| HTTP | HyperText Transfer Protocol | 超文本传输协议 | 80 | 普通网页浏览,不带加密,现在大部分网站升级成 HTTPS(443 端口) |
| SNMP | Simple Network Management Protocol | 简单网络管理协议 | 161 | 网管工具用,监控路由器、交换机、服务器是否正常运行 |
3. 套接字 Socket
套接字 = IP 地址 + 端口号
类比:完整收货地址 = 小区地址(IP)+ 房间门牌号(端口)
唯一确定全网某一台设备上的某一个软件。
1.4 无连接服务与面向连接服务
- 面向连接服务就是在通信双方进行通信之前,必须先建立连接,在通信过程中,整个连接的情况一直被实时地监控和管理。通信结束后,应该释放这个连接。
- 无连接服务是指两个实体之间的通信不需要先建立好连接,需要通信时,直接将信息发送到"网络"中,让该信息的传递在网上尽力而为地往目的地传送。
TCP/IP 协议族在 IP 层之上使用了两个传输协议:
-
一个是面向连接的传输控制协议(TCP),采用TCP时,运输层向上提供的是一条全双工的可靠逻辑信道:
- = 打电话:
- 通信前先建立连接:拨号、对方接听(三次握手);
- 全程维持连接,实时沟通;
- 说完必须主动挂断,释放连接(四次挥手)。
- 优点:说话不会听漏,对方没听清会重复说,有序不乱。
- = 打电话:
-
另一个是无连接的用户数据报协协议(UDP),采用UDP时,运输层向上提供的是一条不可靠的逻辑信道
- = 发短信:
- 不用提前打招呼,编辑完直接发送;
- 没有持续连接,发完就完事;
- 不知道对方有没有收到,不会重发。
- 优点:速度极快,不用等待建立连接。
- = 发短信:
二、UDP 协议
相当于临时工分拣员,干活风格:速度快、省事、不保证包裹不丢、不核对、不回访。
2.1 UDP 数据报
1. UDP 概述
IP 网络层只能把数据包送到对应电脑,分不清电脑里哪个软件。
UDP 只在 IP 的基础上,额外实现两个最小功能:端口复用分用 + 简单差错校验,除此之外啥额外保障都没有。
等于软件几乎直接裸奔在 IP 上,极简设计。
优点:
- 不需要建立连接,零等待时延。
- 电话要拨号等对方接听(三次握手),发短信写完直接发送,不用等待。
- 场景:王者荣耀实时对战、抖音直播语音、视频通话,延迟必须极低,等不起连接建立的时间。
- 无连接状态。
- TCP 服务器要记录每一个用户:收发缓存、序号、拥塞参数,上万用户同时在线会占用大量内存;
- UDP 服务器发完数据就清空记录,完全不记住客户端,百万观众看直播服务器也不会崩。
- 分组首部开销小,只有 8 字节。
- TCP 有 20B 的首部开销,而 UDP 仅有 8B 的开销。数据包体积小,传输更快,占用带宽更少。
- 没有拥塞控制,不会主动降速, 应用层能更好地控制要发送的数据和发送时间。
- 网络堵车的时候,TCP 会主动放慢发送速度避免网络崩溃;UDP 不管堵不堵,该多快发就多快发,因此网络中的拥塞不会影响主机的发送效率。
- 适合直播:画面卡顿可以丢几帧,但不能主动降低清晰度变慢播放;
- 缺点:网络拥堵时大量丢包,消息直接消失。
- UDP支持一对一、一对多、多对一和多对多的交互通信。
- TCP 只能一对一单独通信;
- UDP 可以主播一条数据同时发给上万观众(一对多广播),直播、网课直播全靠这个特性。
2. UDP 首部格式
UDP 数据包 = 8 字节首部 + 应用层数据
![![[Pasted image 20260622102855.png]]](https://img2024.cnblogs.com/blog/3824943/202607/3824943-20260706145829006-847110888.png)
- 四个字段:
- 源端口:你本机客户端的临时短暂端口(49152 以上);
- 目的端口:目标服务器的熟知 / 登记端口(比如 DNS 53);
- UDP 长度:整个 UDP 报文(首部 + 数据)总字节长度;
- 校验和:用来检查传输过程中数据有没有损坏。
2.2 UDP 校验
- 校验和作用
数据包在网线、路由器传输时,有可能电流干扰导致数据错乱。
接收方通过校验和判断数据是否损坏,损坏直接丢弃报文,不会交给上层软件。
- 伪首部(12字节)
在计算校验和时,要在 UDP 数据报之前增加 12B 的伪首部。
- 伪首部不是真实数据包的一部分,不会跟着报文在网络传输,只在计算校验和时临时拼接在 UDP 头部前面,算完直接扔掉。
- 校验和就是按照这个临时的UDP数据报来计算的。
- 伪首部既不向下传送又不向上递交,而只是为了计算校验和。
伪首部里存放 4 类信息:本机 IP、目标服务器 IP、协议标识(标记这是 UDP 报文)、UDP 报文总长度。
- 为什么添加伪首部?
只靠 UDP 自己的首部校验,只能检查端口和数据有没有出错;
但如果传输时 IP 地址被篡改(数据包走错服务器),单纯 UDP 校验发现不了。
伪首部带上了两端 IP 地址,计算校验时会连同 IP 一起校验。
举例:
- 你本来要发给 DNS 服务器 114.114.114.114:53,传输中 IP 被改成别的服务器 IP,端口还是 53。
- 没有伪首部:校验和正常,数据会错分给另一台机器的 53 端口;
- 有伪首部:IP 参与计算,校验和对不上,直接丢弃错误报文。
![![[Pasted image 20260622103043.png]]](https://img2024.cnblogs.com/blog/3824943/202607/3824943-20260706145829568-1630138522.png)
三、TCP 协议
相当于全职严谨分拣员,干活风格:稳扎稳打,保证包裹不丢、不乱序、不多发,收发前打招呼、收发完道别,堵车自动减速。
所有文件下载、网页、微信文字聊天、网盘传输都用 TCP,不能接受消息丢失。
3.1 TCP 协议的特点
TCP 是在不可靠的 IP 层之上实现的可靠的数据传输协议,它主要解决传输的可靠、有序、无丢失和不重复问题。TCP 是 TCP/IP 体系中非常复杂的一个协议,主要特点如下:
- 面向连接
- 通信前必须先建立专属连接,通信结束必须主动断开;没建立连接就不能传输任何业务数据。
- 类比:打电话必须先拨号接通,没接通没法说话;UDP 发短信不用打招呼。
- 只能点对点一对一通信
- 一条 TCP 连接只允许两台设备互相通信,不支持一对多广播。
- 局限:直播、游戏多人实时互动不能用 TCP,只能 UDP。
- 可靠交付(TCP 最核心价值)
- 保证三件事:① 数据不会丢失;② 不会重复收到;③ 全部按发送顺序到达。
- 举例:你发一段 1000 字文档,哪怕网络卡顿、中途丢包,TCP 会自动重传丢失片段,乱序到达的片段自动重新排序,最终接收方拿到完整、有序、唯一的文档。
- 全双工通信
- 接通连接后,两边可以同时互相发送数据,不需要你说完对方才能说。
- 配套设计:连接两端各自有发送缓存、接收缓存。
- 类比:打电话时你说话的同时对方也能插话,双方同时收音、播音;缓存就是双方暂时存没说完 / 没听完的话的记事本。
- 面向字节流
- TCP 完全不关心应用层发给它的数据是一段文字、一张图片还是一条消息,只会把所有数据当成一串连续、无边界的字节数字。
- 坑点举例:微信连续发两条消息「你好」「吃饭了」,应用层是两条独立内容,但 TCP 可能把两段拼接在一起打包发送;接收方 TCP 只会交给应用层一串连续字节,分不清原本两条消息,分割消息需要软件自己处理。
- 对比 UDP:每一条 UDP 数据报都是独立完整消息,天然有边界。
3.2 TCP 报文段
UDP 的传输单元叫「UDP 数据报」,TCP 的传输单元叫 TCP 报文段。
1. TCP 报文段概述
-
TCP 传送的数据单元称为报文段。TCP 报文段既可以用来运载数据,又可以用来建立连接、释放连接和应答。用途不只是传文字、文件数据;建立连接、断开连接、回复确认、紧急指令,全部靠报文段承载;控制类报文甚至可以不带任何应用数据。
-
结构:一个 TCP 报文段分为首部和应用数据两部分,整个 TCP 报文段作为 IP 数据报的数据部分封装在 IP 数据报中。
-
首部长度对比:
- UDP:固定 8B,长度永远不变
- TCP:最小固定 20B,最多 60B,多出的部分是可选扩展项,按 4B 整数倍增加。
2. TCP 报文段格式
![![[Pasted image 20260622103630.png]]](https://img2024.cnblogs.com/blog/3824943/202607/3824943-20260706145830182-856221827.png)
- 序号 seq(4字节)
- TCP 是面向字节流,每一个字节数据都会分配一个独一无二的编号。
- seq = 当前这条报文段携带数据的「第一个字节的编号」。
- 举例子:前面已经完整发送了字节 1~499,本次报文携带 500~999 共 500 个字节,那么这条报文的 seq = 500。
- 补充:SYN、FIN 这类连接控制报文,哪怕不带数据,也会单独占用一个序号。
- 确认号 ack(4字节)
- 占 4B,是期望收到对方下一个报文段的第一个数据字节的序号。
- 若确认号为 N,则表明到序号 N-1 为止的所有数据都已正确收到。
- 只有大写
ACK 确认位 = 1时,这个数字才生效。
- 数据偏移(即首部长度)(4位,即4bit)
-
作用:标记 TCP 头部占多少字节,用来区分「头部结束、数据开始的位置」,指出TCP报文段的数据起始处距离 TCP 报文段的起始处有多远。
-
存储空间:TCP 头部设计时,给 “数据偏移” 这个小格子只分配了4 个二进制位(bit)用来存放数字。格子只有 4 个位置,最多只能写 4 个 0/1,也就是取值范围
0~15(十进制)。- 👉 这里的 4 位,是存储空间大小,是协议标准硬性规定死的,不是算出来的。
-
格子里的数字:代表「多少个 4 字节块」。工程师为了硬件读取效率,规定格子里写数字 N,真实头部长度 = N × 4 字节。
-
单位:单位是 4 字节(32 位),4 位数字最大是 15(1111),
15 × 4 = 60,对应 TCP 首部最大 60 字节。 -
公式:TCP 真实首部字节 = 数据偏移值 × 4 字节
-
举例:没有任何扩展选项时,基础首部 20 字节,
20 ÷ 4 = 5,这个字段就填 5。
- 5 个 1 比特控制标志位(开关,0 关闭 / 1 开启,核心 5 个)
-
急位 URG
- URG=1 时紧急指针生效,报文里有紧急插队数据,不用在接收缓存排队,优先交给应用程序。
- 场景:远程控制强制关机、游戏紧急退出指令。
-
确认位ACK(4字节)
- 连接建立成功之后,所有传输数据的报文,ACK 必须置 1;
- 只有第一次发起连接的 SYN 报文 ACK=0。只要是回复对方的消息,ACK 一定打开。
-
推送位 PSH(Push)
- 接收方收到 PSH=1 的报文,不会等接收缓存填满,立刻把现有全部数据上交 APP。
- 场景:微信实时聊天消息,不用攒一堆再弹窗。
-
同步位 SYN
- SYN=1:这是连接请求 / 连接同意报文,三次握手核心标识,会占用 1 个序号。
-
终止位 FIN(Finish)
- 用来释放一个连接。
- FIN=1:发送方数据全部发完,请求关闭单向传输通道,四次挥手核心标识,占用 1 个序号。
3.3 TCP 连接管理
每个TCP连接都有三个阶段:连接建立、数据传送和连接释放。TCP 连接的管理就是使运输连接的建立和释放都能正常进行。
TCP 连接的建立采用客户/服务器方式。主动发起连接建立的应用进程称为客户(Client),而被动等待连接建立的应用进程称为服务器(Server)。
1. TCP 连接的建立
连接的建立经历以下 3 个步骤,通常称为三次握手。
- 目标:双方互相确认「收发功能正常」,同步各自的初始字节序号 seq,协商连接参数。
- 关键规则:
SYN=1的报文(建连请求)不带数据,但会消耗 1 个序号;只有ACK=1时确认号 ack 生效。
设客户端初始序号:seq = x;服务器初始序号:seq = y
![![[Pasted image 20260622213212.png]]](https://img2024.cnblogs.com/blog/3824943/202607/3824943-20260706145830770-1006664562.png)
- 第一步:客户端 → 服务器
客户机的 TCP 首先向服务器的 TCP 发送连接请求报文段。这个特殊报文段的首部中的同步位 SYN 置1,同时选择一个初始序号 seq=x。TCP 规定,SYN 报文段不能携带数据,但要消耗掉一个序号。
- 报文标记:
SYN=1,ACK=0,seq=x - 人话:客户端拨号,对服务器说:我想和你建立连接,我后续数据字节从编号 x 开始。
- 此时没有确认号,因为
ACK=0。
- 第二步:服务器 → 客户端
服务器的 TCP 收到连接请求报文段后,如同意建立连接,则向客户机发回确认,并为该 TCP 连接分配缓存和变量。在确认报文段中,把 SYN 位和 ACK 位都置 1,确认号是 ack=x+1,同时也为自己选择一个初始序号 seq = y。注意,确认报文段不能携带数据,但也要消耗掉一个序号。
- 报文标记:
SYN=1,ACK=1,seq=y,ack=x+1 - 两层含义:
- SYN=1:服务器同意建立连接,我这边的数据从编号 y 开始;
- ACK=1、ack=x+1:我已经收到了你 x 号的同步信号,期待你下一个字节是 x+1。
- 第三步:客户端 → 服务器
当客户机收到确认报文段后,还要向服务器给出确认,并为该 TCP 连接分配缓存和变量。确认报文段的ACK位置 1,确认号 ack=y+1,序号 seq=x+1。该报文段可以携带数据, 若不携带数据则不消耗序号。
- 报文标记:
ACK=1,seq=x+1,ack=y+1 - 人话:我收到了你的同意信号,期待你下一个数据字节是 y+1。
- 这条报文特点:
- 仅 ACK 标志,没有 SYN,不占用新序号;
- 可以直接携带业务数据(比如你要访问网页的请求);
- 发送完毕,客户端进入连接就绪状态;服务器收到这条报文后,连接正式打通。
2. TCP 连接的释放
通常称为四次挥手。
- 核心逻辑:全双工通道可以单独关闭一条方向。一方发 FIN=1,仅代表「我不再发送数据」,不影响对方继续传数据。
FIN=1报文同样无数据也会消耗 1 个序号。
假设客户端数据先发完,主动提出关闭。
![![[Pasted image 20260622213631.png]]](https://img2024.cnblogs.com/blog/3824943/202607/3824943-20260706145831314-317644587.png)
- 第一步:客户端 → 服务器
客户机打算关闭连接时,向其 TCP 发送连接释放报文段,并停止发送数据,主动关闭 TCP 连接,该报文段的终止位 FIN 置 1,序号 seq=u,它等于前面已传送过的数据的最后一个字节的序号加 1,FIN 报文段即使不携带数据,也消耗掉一个序号。
- 报文:
FIN=1,seq=u - u = 客户端之前发送完所有数据最后一字节序号 +1
- 人话:我这边没有数据要发给你了,请求关闭「客户端→服务器」这条通道。
- 第二步:服务器 → 客户端
服务器收到连接释放报文段后即发出确认,确认号ack=u+1,序号seq=w,等于它前面已传送过的数据的最后一个字节的序号加1。此时,从客户机到服务器这个方向的连接就释放了。
- 报文:
ACK=1,ack=u+1 - 人话:收到你的关闭申请,但我这边还有剩余数据没发完,你先等着,我把剩下消息发给你。
- 当前状态:单向半关闭,服务器仍能持续向客户端发数据。
- 第三步:服务器数据全部传输完毕,服务器 → 客户端
服务器把自己剩余所有数据全部发送完毕后,没有数据再传输,主动向客户端发送 FIN=1 的连接释放报文:
- 报文:
FIN=1,ACK=1,seq=w',ack=u+1 - 人话:服务器告知客户端,我这边也没有数据要发了,准备关闭服务器→客户端这条方向的连接。
- 第四步:客户端 → 服务器
客户端收到服务器的 FIN 报文后,立即回复确认报文:
- 报文:
ACK=1,ack=w'+1 - 人话:收到你的关闭请求,确认双方通道全部关闭。
两端后续状态:
- 服务器:收到客户端发来的这个 ACK 后,直接进入
CLOSED状态,立刻断开连接; - 客户端:发送完 ACK 后进入
TIME-WAIT状态,等待 2MSL(最长报文段寿命)。- 等待目的:防止最后这条 ACK 丢失,服务器超时重传 FIN 时客户端还能补发确认;
- 2MSL 超时结束,客户端才进入
CLOSED,整条 TCP 连接彻底释放。
3.4 TCP 的可靠传输
TCP 能保证数据不丢、不乱、不重复,全靠下面三套机制配合工作,一套负责编号、一套负责回执、一套负责丢包补救。
1. 序号:解决乱序、重复问题
TCP 是面向字节流,每一个字节的数据都会分配唯一序号,不是给整个报文段编号,是给单个字节编号。
两个核心作用:
- 接收端排序
网络里数据包可能走不同路线,后发的包先到、先发的包后到。接收方凭借字节序号,把乱序的数据重新排整齐,再交给应用程序。
举例:你先发 1~500,再发 501~1000;网络先把 501~1000 送到,接收端不会直接上交,先存在缓存,等 1~500 到达后拼接有序。
- 接收端去重
网络故障会导致同一个数据包重复发送到接收方;接收方看到完全一样的字节序号,直接丢弃重复数据,不会重复推送消息给软件。
2. 确认:累计确认机制
TCP 默认使用累计确认,只确认连续、无缺口的字节。
- 确认号规则回顾:ack=N 代表 0~N-1 全部完整收到,下一段期待从 N 号字节开始。
-
关键特性:中间缺一段,后面再多数据都不会确认
-
模拟场景:
- 发送方发出两段:包 A (1~500)、包 B (501~1000)
- 包 A 在路上丢失,只有包 B 先到达接收缓存。
- 虽然缓存里存满 501~1000 的数据,但 1~500 存在缺口,属于不连续数据。
- 接收方只能回复
ack=1,不会回复 ack=1001。 - 发送方看到 ack=1,就知道开头的数据丢了,需要重传。
-
累计确认的好处:不用收到一段就回复一条确认报文,减少网络里的回执包数量,降低带宽开销。
3. 重传:丢包兜底
发送方发完报文后会等待接收方的 ack,如果迟迟收不到回执,就判定数据包丢失,触发重传。分两种场景:超时和冗余 ACK。
-
超时:TCP 每发送一个报文段,就对这个报文段设置一次计时器。计时器设置的重传时间到期但还未收到确认时,就要重传这一报文段。
- 缺点:超时等待时间较长,网络轻微卡顿就要等很久,传输效率低,因此引出优化方案 —— 快重传。
-
冗余ACK(冗余确认)触发快重传:冗余 ACK 就是再次确认某个报文段的 ACK,而发送方先前已经收到过该报文段的确认。连续收到 3 个相同冗余 ACK,不等定时器超时,直接重传缺失报文。
- 例子:发送四段:1500、5011000、10011500、15012000;第一段 1~500 丢失,后面三段全部抵达接收端。接收方每收到一段,都回复 ack=1,连续产生 3 条相同的冗余 ACK。发送方收到第 3 个重复 ack,不等待超时计时器到期,立刻重传缺失的 1~500,大幅缩短等待时间。
3.5 TCP 流量控制
流量控制:解决「发送方发太快,接收方电脑缓存存不下」,是端到端的问题,只看接收主机的负载,由接收方说了算。
- 类比:你疯狂打字发给朋友,朋友手机内存缓存不够,装不下你发的消息,会告诉你 “慢点发,我缓存不够了”。
和数据链路层流量控制的区别:
- 数据链路层:控制相邻两台交换机 / 路由器之间的数据,窗口大小固定不变;
- TCP 运输层:控制两台相隔很远的主机,窗口可以随时动态调整。
1. 接收窗口 rwnd(receive window)
- 含义
接收方电脑里有一块接收缓存,用来存放已经收到、但还没上交微信 / 浏览器等 APP 的数据。
rwnd = 接收缓存当前剩余空闲字节数,代表:我现在最多还能收下多少字节的数据。
- 工作规则
接收方每次回复确认报文(ACK=1)时,都会把当前 rwnd 写到 TCP 头部的「窗口」字段,告诉发送方。
发送方严格遵守:单次发送的数据总量,不能超过 rwnd。
- 实例演示:服务器接收缓存总容量:1000 字节
- 初始状态:缓存全空,剩余 1000 空位 → ACK 报文中
rwnd=1000,发送方可以一次性最多发 1000 字节; - 服务器 APP 处理消息很慢,缓存已经存了 700 字节没读取,只剩 300 空位 → 下次回复 ack 时
rwnd=300,发送方立刻减速,最多只能一次性发 300 字节; - 极端情况:缓存完全占满,没有一点空位 →
rwnd=0,称为零窗口通知,发送方必须立刻停止发送所有数据。
2. 零窗口探测机制
如果收到 rwnd=0,发送方不能永久卡住,需要定时发窗口探测报文:
- 每隔一段时间,发送 1 字节极小探测包;
- 询问接收方:现在缓存腾出空位了吗?新的 rwnd 是多少?
- 一旦接收方 APP 清空缓存,返回 rwnd>0,发送方恢复正常传输。
作用:避免两端永久卡死。
3. 发送窗口上限
发送方真正能发多少,由两个窗口共同约束:发送窗口的上限值=min[rwnd,cwnd]
- rwnd:接收方缓存能承受的上限(流量控制);
- cwnd:网络能承受的上限(下一节拥塞窗口,拥塞控制)。
谁更小,就以谁为标准限速。
3.6 TCP 拥塞控制
拥塞控制:是指防止过多的数据注入网络,保证网络中的路由器或链路不致过载,解决「互联网中间路由器堵了」,是整个网络全局的问题,跟接收方缓存无关。
1. 拥塞窗口 cwnd 和慢开始门限 ssthresh
- 拥塞窗口 cwnd
发送方根据自己估算的网络拥塞程度而设置的窗口值,反映网络的当前容量。
发送方自己设定:一次性能往网络里发多少字节。网络通畅就加大 cwnd,网络拥堵就减小 cwnd。单位是 MSS(单个 TCP 报文最大长度)。
- 慢开始门限 ssthresh
一条分界线:
- 当前
cwnd < ssthresh:执行慢开始算法(指数暴涨窗口) - 当前
cwnd ≥ ssthresh:执行拥塞避免算法(线性缓慢涨窗口)
2. 慢开始算法(连接刚建立,试探网络)
- 规则:
刚建立 TCP 连接,完全不清楚网络承载能力,不能一次性发大量数据:
- 初始化:
cwnd = 1 MSS,一次只发 1 个报文; - 每收到 1 个全新报文的 ACK 确认,
cwnd = cwnd + 1; - 一轮往返时间 RTT 过后,cwnd 直接翻倍,指数增长。
- 举例直观理解:
ssthresh 初始值设为 8 MSS
- cwnd=1 → 发 1 个包;收到 ACK → cwnd=2
- cwnd=2 → 发 2 个包;全部收到 ACK → cwnd=4
- cwnd=4 → 发 4 个包;全部收到 ACK → cwnd=8
- 此时 cwnd == ssthresh,停止慢开始,切换拥塞避免。
- 类比:
刚通车的马路,先放 1 辆车,确认顺畅再翻倍放行,快速试探上限。
3. 拥塞避免算法(到达阈值后,平缓增长)
当 cwnd 超过等于 ssthresh,不再翻倍,增长速度大幅放缓:每经过一整个往返 RTT,cwnd = cwnd + 1,线性缓慢上涨。
- 举例:ssthresh=8,cwnd=8
- 一轮 RTT 后 cwnd=9,再一轮 10…… 一点点放大发送量,避免瞬间把网络挤爆。
4. 网络拥塞的处理
网络出现丢包 = 网络拥堵,分两种丢包场景,处理逻辑完全不一样。
![![[Pasted image 20260622214806.png]]](https://img2024.cnblogs.com/blog/3824943/202607/3824943-20260706145831902-1186471001.png)
- 场景1:超时重传(严重拥堵,整条链路堵塞)
现象:报文发出去,计时器超时都没收到任何 ACK,代表数据包直接堵死在路上丢失。
处理步骤:
- 更新慢开始门限:
ssthresh = cwnd / 2(把上限砍半)(但不能小于2) - 拥塞窗口直接归零重置:
cwnd = 1 - 重新执行慢开始算法,从头缓慢试探网络
逻辑:超时 = 网络彻底堵死,必须大幅减少发包量,缓慢恢复。
- 场景2:连续收到 3 个冗余 ACK(轻微拥堵,少量丢包,网络没卡死)
比如发送 4 段报文,第一段丢失,后三段全部到达,接收方持续重复回复 ack=1,产生 3 条一模一样的确认。
这里配套两个优化机制:快重传 + 快恢复
-
快重传:不等超时计时器,立刻重传丢失的报文,节省等待时间;
-
快恢复(核心区别于超时处理):
ssthresh = cwnd / 2(门限同样减半)cwnd = ssthresh(窗口直接等于新阈值,不用重置到 1)- 直接进入拥塞避免,线性缓慢增大窗口
逻辑:只是少量丢包,网络只是轻微拥挤,不用退回到最原始的慢开始,传输效率更高。

浙公网安备 33010602011771号