05 · 传输层(Transport Layer)

📅 预计 90 分钟 | ⭐ 本章主题:进程间的"端到端"通信,可靠传输的整套机制


5.0 先给直觉:传输层是"快递公司的接单客服"

网络层负责把数据从"城市 A"送到"城市 C"。但送到之后呢?数据到达的是一台主机,而主机上同时开着很多程序:浏览器、微信、邮件、网课……数据该交给哪个程序

传输层就是解决这个问题的——它像快递公司的客服

  • 每一份数据都标了"收件人分机号"(端口号),客服知道该转给哪个部门(进程)。
  • UDP 客服:不管件到没到、坏没坏,扔出去就不管了(快但不保证)。
  • TCP 客服:登记、确认、丢件重发、控制流量,务必"一件不少、顺序不乱"(慢但可靠)。

传输层是整个网络的**"最后一公里配送"**,提供两个重要能力:端口寻址(给进程)可靠传输(TCP)

5.1 端口号:给进程的分机号 ⭐⭐

数据到了主机,怎么找到"具体程序"?

IP 地址找到主机,端口号(port) 找到主机上的具体进程。IP + 端口合起来叫套接字(socket),是"主机 + 进程"的唯一标识。

一次 TCP 连接由四元组唯一确定:
  (源 IP,源端口,目的 IP,目的端口)
例:访问百度首页
  源:192.168.1.5:54321  →  目的:110.242.68.66:80

端口号范围:0 ~ 65535(16 位)。常见的几个要背:

端口 服务 端口 服务
21 FTP(文件传输控制) 53 DNS(域名解析)
22 SSH(远程登录) 80 HTTP(网页)
25 SMTP(发邮件) 443 HTTPS(加密网页)

💡 记忆口诀"80 网页、443 加密网页、53 DNS、21 FTP、22 SSH"。记这几个高频的,其他见到查表即可。

⚠️ 常见错误

  1. 把端口和 IP 混为一谈:IP 找主机,端口找进程,两个都必需。
  2. 把 53 记成 HTTP:53 是 DNS(域名解析);80/443 才是网页。
  3. 四元组记不齐:完整标识一条连接要"源 IP、源端口、目的 IP、目的端口"四项,缺一项就可能张冠李戴。

5.2 UDP:轻量级"只管送" ⭐⭐⭐

寄平信,不挂号

UDP(User Datagram Protocol,用户数据报协议)无连接、不可靠的传输协议。像寄平信:写好地址就投进邮筒,不确认收到、不保证顺序、不保证不丢。

特点:

  • 无连接:发之前不用"握手",直接发。
  • 不可靠:不确认、不重传、不保证顺序。
  • 首部小(8 字节),开销低。
  • 支持一对多/一对全:适合广播和组播。

UDP 报文段结构(首部就 4 个字段):

| 源端口(16) | 目的端口(16) |
| 长度(16)   | 校验和(16)   |
|        数据...           |

适合用 UDP 的场景:实时性优先、可以容忍少量丢失——视频直播、语音通话(丢一帧画面没事,卡顿才难受)、DNS 查询、DHCP。

💡 一句话UDP = 平信:快、省、不管到没到。适合"宁可少一点也不能慢"的应用。

⚠️ 常见错误

  1. 以为 UDP 一定比 TCP"坏":UDP 在实时场景(视频/语音)是更好的选择,"不可靠"是特性不是缺陷。
  2. 把 UDP 首部记成 20 字节:TCP 首部一般 20 字节,UDP 首部只有 8 字节
  3. 以为 UDP 能做广播:TCP 是点对点的连接,做不了广播;UDP 可以广播/组播。

5.3 TCP 报文段:可靠传输的"包裹单" ⭐⭐

TCP(Transmission Control Protocol,传输控制协议)面向连接、可靠、按字节流的传输协议。像寄挂号信:编号、签收、丢件补发。

TCP 报文段首部(标准 20 字节)关键字段:

| 源端口(16) | 目的端口(16) |
|     序号 sequence(32)     |
|   确认号 ack(32)          |
| ... | 标志位(URG ACK PSH RST SYN FIN) | 窗口大小 |
| 校验和(16) | 紧急指针(16) |
|        数据...           |

关键字段含义:

  • 序号(seq):本报文段数据第一个字节的字节号(TCP 是字节流,按字节编号)。
  • 确认号(ack)期望收到对方下一个字节的序号,等于"对方已经收到 ack−1 之前的所有字节"。
  • 标志位
    • SYN:请求建立连接(握手用)。
    • ACK:确认号有效(几乎每个包都带)。
    • FIN:请求关闭连接(挥手用)。
    • RST:异常重置连接。
    • PSH:立即交付应用层。
  • 窗口大小:告诉对方"我的接收缓冲区还能收多少",是流量控制的依据。

💡 记忆口诀"序号数第一个字节,确认号是期待下一个,SYN 建连、FIN 断开"

⚠️ 常见错误

  1. 把序号当"第几个包":序号是字节号不是包号——一个包可能带 1460 字节数据,下一个包序号跳着走。
  2. 确认号含义记反:确认号 ack = "我期待你下一个字节的号",代表它之前的都已收到。
  3. 首部长度记混:TCP 标准首部 20 字节,UDP 8 字节。

5.4 三次握手:建立连接 ⭐⭐⭐

通话前先对好暗号

TCP 是面向连接的,通信前必须先建立连接。三次握手(three-way handshake)的过程:

客户端 C                          服务器 S
  |                                 |
  |── SYN=1, seq=x ────────────────▶|  ① C 说:我要连你(SYN,带上我的初始序号 x)
  |                                 |
  |◀── SYN=1, ACK=1, seq=y, ack=x+1 ─|  ② S 说:收到,我也要连你(SYN+ACK,带上我的初始序号 y,确认 x)
  |                                 |
  |── ACK=1, seq=x+1, ack=y+1 ────▶|  ③ C 说:确认收到你的 y(ACK)
  |                                 |
  |◀════ 连接建立,开始传数据 ════▶|

为什么是三次不是两次?——第二次的 SYN 和 ACK 要分清楚职责:① 让服务器确认"客户端能发";② 让客户端确认"服务器能收能发";③ 让服务器确认"客户端能收"。如果只两次,服务器无法确认"客户端收到了我的 SYN",可能造成半连接(服务器以为连上了,客户端其实没收到)。

💡 记忆口诀"三次握手:问→应→确认"。第一次问,第二次应并回问,第三次确认。核心是让双方都确认"你能收到我的话"。

⚠️ 常见错误

  1. 把第三次握手省掉:第三次 ACK 缺了,连接建立不完整(服务器认为建立,客户端可能没收到,浪费服务器资源——这就是 SYN 洪泛攻击的原理)。
  2. 第二次为什么同时带 SYN 和 ACK:因为 TCP 连接是双向的,服务器也要建立自己的连接方向,把应答和请求合并在一个包里。
  3. 握手之后才传数据:三次握手完成前不会传应用数据,第三次握手包可以顺带带数据(但在教学考试里一般说第三次起才开始传)。

5.5 四次挥手:释放连接 ⭐⭐⭐

各说各的再见

TCP 是全双工,两条方向的连接独立关闭,所以要四次挥手(four-way handshake)

客户端 C                             服务器 S
  |                                    |
  |── FIN=1, seq=u ──────────────────▶|  ① C 说:我不再发了(关闭我的发送方向)
  |                                    |
  |◀── ACK=1, ack=u+1 ────────────────|  ② S 说:收到(但 S 可能还有数据要发)
  |                                    |
  |◀── FIN=1, seq=w ──────────────────|  ③ S 说:我的数据发完了,我也要关(关闭它的发送方向)
  |                                    |
  |── ACK=1, ack=w+1 ────────────────▶|  ④ C 说:收到,关闭

几个要点:

  • 为什么 ③ 不能和 ② 合并:因为服务器收到 FIN 后,可能还有数据要发,所以先只确认(②),等数据发完再发 FIN(③)。这中间的时间差导致多一次挥手。
  • TIME_WAIT:客户端发完第四次 ACK 后要等 2MSL(两倍最大报文段寿命),确保最后的 ACK 能被服务器收到、旧连接的数据在网络上彻底消失,防止影响新连接。
  • 为什么需要四次:每个方向的"关闭"都需要一次"请求 FIN + 一次确认 ACK",两个方向共四次。

💡 记忆口诀"挥手四次:我关→你确认→你关→我确认"。全双工两条路,各走各的流程。

⚠️ 常见错误

  1. 为什么不是三次:因为服务器可能还有数据要发,不能和 ② 一起关。数据发完才发 FIN。
  2. TIME_WAIT 是在谁身上主动关闭方(先发 FIN 的一方)在发完最后 ACK 后进入 TIME_WAIT,等待 2MSL。
  3. 挥手和握手的包都混了:握手用 SYN 开头,挥手用 FIN 开头;握手 3 包、挥手 4 包。

5.6 可靠传输:确认、序号、重传 ⭐⭐⭐

挂号信的三件套

TCP 怎么保证"数据不丢、不乱"?靠三件套:

  1. 序号(sequence number):给每个字节编号,接收方按序号重排,乱序也能恢复。
  2. 确认(acknowledgment):接收方告诉发送方"我收到哪了"。
  3. 重传(retransmission):超时没收到确认 → 发送方重发

机制细节:

  • 确认与重传(ARQ):发送方发出数据后启动重传计时器,若在超时时间内没收到 ACK,就认为丢了,重新发送。
  • 累积确认:TCP 的确认是"累积"的——确认号 ack=n 表示"n−1 及以前的所有字节都收到了",不用对每个包单独确认。
  • 快速重传:如果连续收到 3 个重复的 ACK,说明中间丢了包,发送方不等超时立即重传(更快)。
A 发 seq=1..100, 101..200, 201..300
  但 101..200 丢了
B 收到 1..100  → 发 ACK=101(期望 101)
B 收到 201..300 → 发现缺 101..200,仍发 ACK=101(重复确认)
A 连收 3 个重复 ACK=101 → 不等超时,立即重传 101..200(快速重传)

💡 记忆口诀"序号防乱序,确认报进度,超时或三个重复 ACK 就重传"

⚠️ 常见错误

  1. 超时重传 vs 快速重传分不清:超时重传是"等计时器到点";快速重传是"收到 3 个重复 ACK 立即发",更快。
  2. 累积确认不是"每个包单独回一个":ack=n 覆盖 n−1 之前所有字节,能减少确认包数量。
  3. 确认号是"期望的下一个序号"不是"已收到的最后一个序号"ack=x+1 表示已收到 x,期待 x+1。

5.7 滑动窗口与流量控制 ⭐⭐⭐

收件箱放不下了,请"慢点发"

接收方缓冲区是有限的。如果发送方不管不顾猛发,接收方缓冲区会溢出丢包流量控制(flow control) 就是"让发送方的发送速度适配接收方的接收能力"。

实现机制:滑动窗口 + 窗口通告

  • 接收方在 ACK 里带一个**窗口(window)**字段,告诉发送方"我这还能再收多少字节"。
  • 发送方维护一个发送窗口:窗口内的字节已发但未确认,可以继续发;窗口满了就停,等 ACK 把窗口"前移"。
发送窗口(大小 4 个字节序号):
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | ...
  ↑已确认 ↑←←窗口内(可发/已发)→→↑ ←未发,等窗口前移

收到对 1、2 的确认 → 窗口右移两格,可继续发 5、6
  • 滑动窗口 VS 停等协议:最早的协议"发一个等一个"(停等),效率极低;滑动窗口允许连续发多个再等确认,充分利用带宽。
  • 窗口大小 = min(接收方通告窗口, 拥塞窗口)——流量控制管"接收方能力",拥塞控制管"网络能力",两个都满足才发。

💡 记忆口诀"窗口=还没被确认但可以发的额度,收据(ACK)一来窗口就往前滑"

⚠️ 常见错误

  1. 把流量控制和拥塞控制混了流量控制管"接收方缓冲区装不下"(端到端、靠窗口通告);拥塞控制管"网络堵了"(靠拥塞窗口、慢启动等)。前者治"下游收不动",后者治"路上堵车"。
  2. 窗口是"字节数"不是"包数":滑动窗口以字节(序号)为单位。
  3. 以为窗口固定不变:窗口随 ACK 动态滑动,接收方还能随时通告更小的窗口来压速度(甚至通告 0 停止发送)。

5.8 拥塞控制 ⭐⭐

路上堵车了,别一股脑往里挤

拥塞控制(congestion control) 处理的是"网络中间堵了"——路由器的队列满了、大量包被丢弃。发送方要"收敛"自己的发送速率。

四种机制(阶段),记忆按顺序:

  1. 慢启动(slow start):拥塞窗口从 1 开始,每收到一个 ACK 窗口翻倍(指数增长)。不是真的"慢",是从小到大探路。
  2. 拥塞避免(congestion avoidance):窗口涨到慢启动阈值(ssthresh)后,改为线性加一(每个往返周期 +1),缓慢增长。
  3. 快重传(fast retransmit):收到 3 个重复 ACK → 立即重传丢失的报文。
  4. 快恢复(fast recovery):把 ssthresh 降为当前窗口的一半,窗口也从半值继续线性增长。
窗口大小
  ↑
  |  ← 慢启动(指数增)
  |     ← 到阈值 → 拥塞避免(线性增)
  |                ↓ 发生丢包(3 个重复 ACK 或超时)
  |      ← 快恢复:ssthresh 减半,窗口减半,再线性爬
  +──────────────────→ 时间

💡 记忆口诀"慢启动指数探路,拥塞避免线性爬,丢包减半再恢复"。记住"快"字辈的两个动作都发生在丢包时。

⚠️ 常见错误

  1. 慢启动不是"慢慢发":它是指数增长快速试探,"慢"指从很小(1 个报文段)起步。
  2. 流量控制 vs 拥塞控制的触发对象:流量控制看接收方的窗口通告;拥塞控制看网络的丢包/拥塞信号。
  3. 快恢复和快重传是一对:收到 3 个重复 ACK 时"快重传"丢的包,同时"快恢复"把阈值和窗口减半,不是降到 0 重来(只有超时才从慢启动重新开始)。

5.9 TCP 的连接状态:连接是有"生命周期"的 ⭐

建立、使用、关闭,每一步都有名字

TCP 连接不是一个瞬间动作,而是一个状态机——从创建到关闭,连接处于不同的状态。记住几个高频状态:

状态 出现在 含义
LISTEN 服务器 服务器在监听,等待连接请求
SYN-SENT 客户端 客户端已发 SYN,等服务器应答
ESTABLISHED 双方 连接建立成功,正在传数据
FIN-WAIT-1 / FIN-WAIT-2 主动关闭方 已发 FIN / 已收对方 ACK,等对方 FIN
CLOSE-WAIT 被动关闭方 已回 ACK,等自己数据发完再发 FIN
TIME-WAIT 主动关闭方 发完最后 ACK,等 2MSL 让旧包消散

配合四字口诀理解状态路径:

握手:    CLOSED → LISTEN(服务器) / SYN-SENT(客户端) → ESTABLISHED
使用:    ESTABLISHED(传数据)
挥手:    ESTABLISHED → FIN-WAIT-1 → FIN-WAIT-2 → TIME-WAIT(主动方,等2MSL)
          同时被动方:ESTABLISHED → CLOSE-WAIT → LAST-ACK → CLOSED

💡 记忆口诀"握手进 ESTABLISHED,挥手走 TIME-WAIT;谁先发 FIN 谁负责最后等 2MSL"

⚠️ 常见错误

  1. TIME-WAIT 只属于主动关闭方:被动关闭方发完 FIN 收到 ACK 就 CLOSED 了,不用等 2MSL。
  2. CLOSE-WAIT 是被动关闭方的状态:它代表"我收到你的 FIN 了,但我还在等自己的数据发完"。
  3. LAST-ACK 不要和 FIN-WAIT 混:FIN-WAIT 是主动方等对方 FIN;LAST-ACK 是被动方发完自己的 FIN 等对方最后确认。

5.10 TCP 与 UDP 总对比 ⭐⭐⭐

两个协议一张表看懂

对比维度 TCP UDP
连接 面向连接(三次握手) 无连接
可靠性 可靠(确认/重传/序号) 不可靠(尽力而为)
顺序 保证按序交付 不保证顺序
传输单位 字节流(无边界) 用户数据报(有边界)
首部开销 20 字节 8 字节
流量/拥塞控制
支持广播/组播 不支持(点对点) 支持
典型应用 网页 HTTP、文件 FTP、邮件 SMTP、SSH 视频直播、语音、DNS、DHCP

为什么 TCP 是"字节流"而 UDP 是"报文":TCP 把应用层数据看成连续的字节流,按自己的节奏切块打包发送(所以有"序号""重组");UDP 把应用层每次 write 的数据原样作为一个报文发送(有边界,一次发一个)。

怎么选:需要完整、有序、可靠 → TCP(网页、文件、邮件);要快、可容忍少量丢失 → UDP(视频、语音、实时游戏)。

💡 记忆口诀"TCP 靠谱慢,UDP 快不稳;要完整选 TCP,要实时选 UDP"

⚠️ 常见错误

  1. 以为 UDP 不能用于可靠场景:UDP 之上可以自己实现可靠性(如 QUIC 协议在 UDP 上做可靠传输),UDP 只是"不内置"可靠机制。
  2. 把 DNS 记成 TCP:DNS 查询用 UDP(53 端口),快速一问一答;只有区域传输等少数情况用 TCP。
  3. TCP 是字节流、UDP 是报文:这一点选择题常考——TCP 无消息边界,UDP 有消息边界。

🧠 记忆口诀

  • 传输层两件事:端口找进程(socket=IP+端口),TCP 保可靠。
  • TCP 三件套:序号防乱序、确认报进度、超时/重复 ACK 就重传。
  • 三次握手:问→应→确认;四次挥手:我关→你确认→你关→我确认。
  • SYN 建连、FIN 断开、ACK 确认、RST 重置
  • 流量控制治"接收方装不下"(窗口通告),拥塞控制治"路上堵车"(慢启动/拥塞避免)
  • 慢启动指数探路,拥塞避免线性爬,丢包减半快恢复

⭐ 考点清单

  1. 端口号的作用、常见端口(21/22/25/53/80/443)
  2. UDP 特点:无连接、不可靠、8 字节首部;适合实时场景
  3. TCP 特点:面向连接、可靠、字节流、20 字节标准首部
  4. TCP 报文段关键字段:序号、确认号、SYN/ACK/FIN 标志、窗口
  5. 三次握手的完整流程与各包含义、为什么必须是三次
  6. 四次挥手流程、为什么是四次、TIME_WAIT 与 2MSL
  7. 可靠传输:序号重排、累积确认、超时重传、快速重传(3 个重复 ACK)
  8. 滑动窗口与流量控制:窗口通告、窗口滑动
  9. 拥塞控制四阶段:慢启动、拥塞避免、快重传、快恢复
  10. 流量控制(端到端、接收方)与拥塞控制(网络)的区别
  11. TCP 连接状态:ESTABLISHED、FIN-WAIT、CLOSE-WAIT、TIME-WAIT(2MSL)
  12. TCP 与 UDP 总对比:字节流 vs 报文、20 vs 8 字节、是否支持广播

📌 中英术语表

中文 English 说明
传输层 transport layer 进程间端到端通信
端口号 port number 标识主机上的具体进程
套接字 socket IP + 端口,标识一个端点
UDP User Datagram Protocol 无连接、不可靠、8 字节首部
TCP Transmission Control Protocol 面向连接、可靠、字节流
报文段 segment 传输层的数据单元
序号 sequence number 数据首字节的字节号
确认号 acknowledgment number 期望收到的下一字节序号
标志位 flag SYN/ACK/FIN/RST 等
三次握手 three-way handshake 建立连接的三次交互
四次挥手 four-way handshake 释放连接的四次交互
超时重传 timeout retransmission 计时器到点未确认则重发
快速重传 fast retransmit 收到 3 个重复 ACK 立即重发
累积确认 cumulative acknowledgment ack=n 表示 n−1 前都收到
滑动窗口 sliding window 未确认但可发的字节额度
流量控制 flow control 适配接收方能力,靠窗口通告
拥塞控制 congestion control 适配网络状态,避免拥堵
慢启动 slow start 窗口指数增长探路
拥塞避免 congestion avoidance 窗口线性增长
快恢复 fast recovery 丢包后减半窗口恢复
最大报文段寿命 MSL 报文在网络中的最长存活时间
连接状态 connection state LISTEN/ESTABLISHED/FIN-WAIT/TIME-WAIT 等
字节流 / 报文 byte stream / datagram TCP 无边界字节流,UDP 有边界报文
QUIC QUIC 基于 UDP 实现可靠传输的新协议