miniyuan
传输层
传输层总览
作用与抽象
- 传输层提供端到端的逻辑通信(“看上去像直接通信,实际是由传输层在主机间实现进程到进程的通信”)。
- 传输层端点是主机内的进程,用**套接字(socket)**标识:
socket = (IP 地址 : 端口号)例:
socket = (192.169.1.20 : 2028)
主要功能
- 复用与分用(基于端口)
- 两类传输服务协议:无连接/不可靠(UDP)与面向连接/可靠(TCP)
- 可靠传输、流量控制、拥塞控制、连接管理(建立/释放)
- 提供给上层的抽象:面向报文(UDP)或面向字节流(TCP)
端口与复用/分用
端口号
-
用 16 位端口号标识传输层的软件端口(本地意义)。
-
端口分类:
类型 端口范围 熟知端口(Well-known) 0 — 1023 登记端口(Registered) 1024 — 49151 短暂/私有端口(Ephemeral) 49152 — 65535
复用/分用示意
- IP 数据报携带目标 IP + 传输层首部(含目的端口),操作系统根据端口将数据分发到对应进程(复用与分用)。
UDP(User Datagram Protocol)
特点(要点)
- 无连接、尽最大努力交付(不可靠)
- 面向报文(保留上层报文边界,不拆分/合并)
- 头部开销小,固定 8 字节
- 适合实时或短小突发流(RTP、DNS、DHCP、SNMP、TFTP 等)
UDP 首部(8 字节)
┌──────┬──────┬──────┬──────┐
│ SrcP │ DstP │ Len │Checksum│
│ 2B │ 2B │ 2B │ 2B │
└──────┴──────┴──────┴──────┘
- 字段:源端口、目的端口、UDP 长度(头+数据)、检验和(覆盖伪首部+UDP首部+数据)
UDP 校验和(概要)
- 计算时在 TCP/UDP 报文前加 12 字节的伪首部(源 IP、目的 IP、协议号、UDP 长度)。
- 校验和采用 16-bit 逐字(16-bit)反码和,结果取反码作为检验和。
- 若校验和计算结果为 0,报文中存放 0 表示“无校验和”(在 IPv4 中可为 0;IPv6 强制校验和)。
注:示例校验和计算流程为对伪首部、UDP 首部和数据按 16 位求和,若有溢出进位则回卷,再取反码。
TCP(Transmission Control Protocol)
基本特性
- 面向连接,在不可靠 IP 上提供可靠、按序的字节流传输。
- 面向流:TCP 对字节流分段,发送方/接收方不保证应用层消息边界对应。
- 连接端点为套接字(IP:端口)。同一 IP 上可有多个连接(不同远端端口或远端 IP)。
TCP 报文段首部
0B 1B 2B 3B 4B
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number (SEQ) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number (ACK) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Offset | Rsrvd | Flags | Window Size |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 字段 | 位数 | 说明 |
|---|---|---|
| Source Port | 16位 | 源端口号。发送方的端口号,用于标识发送应用程序 |
| Destination Port | 16位 | 目的端口号。接收方的端口号,用于标识接收应用程序 |
| Sequence Number (SEQ) | 32位 | 序列号。用于数据流排序: 如果是 SYN 包,表示初始序列号(ISN) 如果是数据包,表示本段数据第一个字节的序列号 |
| Acknowledgment Number (ACK) | 32位 | 确认号。只有当 ACK 标志位为 1 时才有效,表示期望收到的下一个字节的序列号 |
| Offset | 4位 | 数据偏移。实际就是 TCP 首部长度,以 32 位(4B)为单位。最小值为 5(20B),最大值为 15(60B) |
| Rsrvd (Reserved) | 4位 | 保留位。预留将来使用,必须为 0 |
| Flags | 8位 | 标志位。每个标志位占 1 位,用于控制连接状态: CWR (Congestion Window Reduced):拥塞窗口减少 ECE (ECN-Echo):ECN 回显 URG (Urgent):紧急指针字段有效 ACK (Acknowledgment):确认号字段有效 PSH (Push):推送数据,接收方应尽快交给应用层 RST (Reset):重置连接 SYN (Synchronize):同步序列号,用于建立连接 FIN (Finish):发送方已完成数据发送 |
| Window Size | 16位 | 窗口大小。用于流量控制,表示发送方愿意接收的字节数(从确认号开始) |
| Checksum | 16位 | 校验和。对整个 TCP 段(首部 + 数据)进行错误检测,还包括伪首部(含源 IP、目的 IP 等) |
| Urgent Pointer | 16位 | 紧急指针。只有当 URG 标志位为 1 时才有效,表示紧急数据在段中的结束位置 |
注:
- TCP 固定首部长度:不含选项时为 20 字节
- TCP 最大首部长度:含选项时可达 60 字节
- 伪首部(Pseudo Header): 校验和计算时,需要 12 字节信息(源 IP、目的 IP、协议号、TCP 长度)。 否则校验和中不包含 IP 信息,也即接收方的传输层无法利用其确定 IP 分组是否是正确传给自己的。 但是为了职责分离,传输层不应直接操作 IP,故而向网络层索要服务,网络层给予它一个伪首部用于临时计算,并不传输。
0B 1B 2B 3B 4B
|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source IP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination IP Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Padding Zero | Protocol | TCP Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- 标志位位于 TCP 头部的第 14 个字节,共 8 位:
| 标志 | 名称 | 含义 |
|---|---|---|
| SYN | 同步标志 | 请求建立连接 |
| ACK | 确认标志 | 确认号有效 |
| FIN | 结束标志 | 请求断开连接 |
| RST | 重置标志 | 连接异常中断 |
| PSH | 推送标志 | 接收方应尽快交给应用层 |
| URG | 紧急标志 | 紧急指针有效 |
套接字与 Socket API(简述)
- socket() 创建套接字,bind()/listen()/accept() 用于服务器端,connect()/send()/recv() 等用于客户端和服务器的数据交互。
- 在内核中每个连接有传输控制块(TCB)保存连接状态(IP/端口、本地/远端等)。
可靠传输机制(ARQ)
停等 ARQ(Stop-and-Wait)
- 每次发送一个分组并等待确认(ACK)。
- 简单但信道利用率低,受 RTT 与帧发送时间比例影响。
- 要点:编号、超时重传、保留已发送副本。
连续 ARQ / 滑动窗口(Sliding Window)
- 发送方允许一次发送多个分组(窗口大小 W_T),接收方维护接收窗口(W_R)。
- 常见实现:
- Go-Back-N:接收方只累积确认,发送方回退并重传自丢失分组之后的所有分组。通常 W_R=1。
- Selective Repeat(选择重传):接收方可缓存乱序分组,发送方只重传缺失分组。需要 W_T > W_R > 1。
- 累积确认(cumulative ACK):接收方确认按序到达的最后一个字节/分组,减少确认数量但无法指示单个分组的到达。
连续 ARQ 与停等对比表
| 特性 | 停等 ARQ | 连续 ARQ |
|---|---|---|
| 一次发送分组数 | 1 | 多个 |
| 传输控制 | 停等 | 滑动窗口 |
| 确认方式 | 单独确认 | 单独或累积确认 |
| 超时计时器 | 每分组 | 每分组(或按实现) |
| 重传 | 一个分组 | 回退 N 或选择重传 |
TCP 的可靠传输实现细节
序号与确认(以字节为单位)
- TCP 使用字节序号,确认基于序号(ACK 表示期望下一个字节序号)。
- 必须保留已发送但未确认的数据以便重传。
- 接收方缓存:按序到达未交给应用的数据 + 乱序到达的数据块。
RTT 估计与 RTO
- 平滑 RTT(RTTS):
RFC 6298 推荐 α = 1/8 = 0.125
- Karn 算法(修正):对发生重传的报文段不使用该样本更新 RTTS;每次重传使 RTO 增大(乘以 γ,典型 γ = 2)。
Nagle 算法 与 糊涂窗口综合症(Silly Window Syndrome)
- 糊涂窗口综合症:收发双方以极小碎片(例如 1 字节)交互,导致效率极低(例如 1 字节数据占 41 字节 IP+TCP)。
- Nagle 算法(发送端):
- 如果有未被确认的小片段,则缓冲后续小片段,直到先前数据被确认或缓冲数据达到 MSS 或超时。
- 接收方解决方法:
- 等待直到接收缓存有足够空间容纳一个最大报文段或达到一半空闲空间再发送窗口更新。
持续计时器(Persistence Timer)
- 用于零窗口探测:当对端通告 rwnd = 0 时,启动持续计时器,到期发送 1 字节的零窗口探测以获知窗口更新,避免死锁。
流量控制(Receiver Window)
- 接收方通告 rwnd(接收窗口大小)表示可接收剩余字节数。
- 发送方实际可发送的窗口:
rwnd:由接收方通告; cwnd:拥塞窗口(由拥塞控制决定)
拥塞控制(TCP Reno 为例)
总体思想
- 使用发送端维护的拥塞窗口 cwnd 来反映网络可用容量,配合接收方 rwnd 限制真实发送窗口。
- 拥塞事件判断:
- 重传定时器超时:严重,假定网络拥塞
- 收到 3 个重复 ACK:轻度拥塞 / 丢失个别分组
慢开始(Slow Start)
- 初始 cwnd = 1(报文段单位,旧标准 1-2,RFC 5681 推荐 2-4)
- 每收到一个对新报文段的确认,cwnd 加 1(按报文段计);每轮传输 cwnd 指数级增长。
- 设置慢开始门限 ssthresh,当 cwnd >= ssthresh 时转为拥塞避免。
拥塞避免(Congestion Avoidance)
- 当 cwnd >= ssthresh 时,每经过一个 RTT(或每收到一个轮次中的 ACK)使 cwnd 线性增加(典型为每 RTT 增加 1 MSS)。
快重传与快恢复(Fast Retransmit / Fast Recovery)
- 快重传:收到 3 个重复 ACK 立即重传怀疑丢失的分段(避免超时等待)。
- 快恢复(Reno):在收到 3 dupACK 时:
- ssthresh = cwnd / 2
- cwnd = ssthresh (或 cwnd = ssthresh + 3MSS,具体实现略有差异)
- 进入拥塞避免而非慢开始(避免退回到指数增长)
算法流程概览
- 连接建立:cwnd 初始值,慢开始进行
- 当发生 3 dup ACK:触发快重传 + 快恢复(避免慢开始)
- 当发生超时:ssthresh = cwnd/2,cwnd = 1,进入慢开始
路由器队列管理与 AQM(主动队列管理)
Tail-drop(尾部丢弃)
- FIFO 队列,满则丢弃到达分组,可能导致全局同步(大量连接同时进入慢开始)。
RED(Random Early Detection)
- 参数:Th_min、Th_max、p_max
- 维护平均队列长度 Lav:
- 若 Lav < Th_min:p = 0(接受)
- 若 Lav > Th_max:p = 1(丢弃)
- 若 Th_min <= Lav <= Th_max:以概率 p(0 < p < 1)随机丢弃入队分组(可使不同连接随机退避,减轻全局同步)
- 丢弃概率 p 通常从 0 线性增至 p_max。
TCP 连接管理
三次握手(建立连接)
- 客户端发送 SYN, seq = x
- 服务器应答 SYN=1, ACK=1, seq = y, ack = x+1
- 客户端发送 ACK=1, seq = x+1, ack = y+1
- 目的:确认双方存在、协商初始序号与一些选项、防止旧请求误用
四次挥手(释放连接)
- 主动方发送 FIN (seq = u)
- 被动方 ACK (ack = u+1),进入 CLOSE_WAIT
- 被动方发送 FIN (seq = w),主动方 ACK (ack = w+1)
- 主动方等待 TIME_WAIT(通常 2×MSL)以确保最后 ACK 的可靠传输与消除已延迟分组
TCP 有限状态机(简述)
- 典型状态:CLOSED, LISTEN, SYN_SENT, SYN_RCVD, ESTABLISHED, FIN_WAIT_1, FIN_WAIT_2, CLOSING, TIME_WAIT, CLOSE_WAIT, LAST_ACK
- 状态转换由 SYN/ACK/FIN/RST/超时等触发
保活计时器(Keepalive)
- 用于检测长时间空闲连接是否仍然存活;
- 常见实现:2 小时静默后发探测(若连续若干次无应答则断开)。
UDP 与 TCP 的对比(表格化)
| 特性 | UDP | TCP |
|---|---|---|
| 连接类型 | 无连接 | 面向连接 |
| 可靠性 | 不保证 | 提供可靠按序交付 |
| 流量控制 | 无 | 有(接收方窗口 rwnd) |
| 拥塞控制 | 无 | 有(cwnd、慢开始、快重传等) |
| 面向 | 报文(message) | 字节流(stream) |
| 首部开销 | 8 字节 | 最少 20 字节(可变) |
| 适用场景 | 实时、多播、简单查询(DNS、RTP) | 文件传输、HTTP、邮件等需要可靠传输的应用 |
DNS(基于 UDP 的应用示例)
设计目标与层次结构
- 解决主机名可读性、可变 IP 地址问题、别名、负载均衡等。
- 采用分布式层次结构:Root → Top-Level(TLD)→ 权威(Authoritative)→ 本地域名服务器
- 13 个根服务器(逻辑)原因:传统 UDP DNS 报文的 512B 限制,限制了可返回的根记录数量(示例计算见课件说明)。
查询方式
- 迭代查询(iterative):本地 DNS 向上级询问并返回下一步的 NS 地址,由本地重复查询。
- 递归查询(recursive):请求的服务器尽可能返回最终答案(降低客户端负担,但服务器开销大)。并非所有根/TLD 支持递归。
DNS 报文格式(概述)
- 头部 12 字节(ID 2B,Flags 2B,Qdcount/Ancount/Nscount/Arcount 各 2B)
- 问题部分(Question):QNAME、QTYPE、QCLASS
- 答案/授权/附加:资源记录(RR)
- 报文类型:Query / Reply
DNS 的可靠性与防护措施
- 主/辅权威服务器(主从复制)用于高可用与一致性
- 本地缓存可显著减少解析延迟
- 安全威胁:缓存中毒、伪造应答、DDoS(向根或 TLD 发大量请求)
- 典型防护:DNSSEC(签名验证)、递归限制、缓存策略、来源验证等
小结与重要公式/要点
- socket = (IP : 端口)
- UDP 头部固定 8B,校验和覆盖伪首部 + UDP首部 + 数据
- TCP 可靠传输基于字节序号与确认;必须保留已发送但未确认的数据
- RTT 平滑更新:
- 实际可发送窗口:
- 拥塞控制要点:慢开始(指数增长)、拥塞避免(线性增长)、快重传、快恢复、超时退回慢开始
- AQM(如 RED)用于避免尾部丢弃导致的全局同步