Files
cs-note/hhs/NETWORK/02-链路层/02-CSMA-CD与以太网退避.md
T
2026-05-27 00:12:00 +08:00

9.8 KiB
Raw Blame History

tags, create time
tags create time
计算机网络
CSMA-CD
以太网退避
冲突检测
碰撞域
全双工
半双工
2026-05-17 23:00

CSMA/CD 与以太网退避

概述

CSMA/CD(Carrier Sense Multiple Access / Collision Detection,载波监听多路访问/冲突检测)是早期共享式以太网的 MAC 子层协议。虽然现代交换式以太网已不再使用它,但理解其原理对掌握网络演进和碰撞域概念至关重要。

[!QUESTION] 为什么需要 CSMA/CD? 在共享介质(如同轴电缆或 Hub 集线器)上,多台设备共用同一根网线。如果没有协调机制,两台同时发送会导致信号叠加破坏——就像两个人同时在同一频道说话,谁也听不清。

CSMA/CD 工作流程

flowchart TD
    Start["有帧要发送"] --> Wait["等待信道空闲?"]
    Wait -->|"空闲"| Send["开始发送"]
    Wait -->|"忙碌"| Wait
    Send --> Check{"是否在 512bit<br/>时间内检测到冲突?"}
    Check -->|"否"| Done["发送完成 ✅"]
    Check -->|"是"| Collide["发生冲突 → 发送 Jam Signal"]
    Collide --> Backoff["指数退避算法计算等待时间"]
    Backoff --> Retry{"重传次数 < 16?"}
    Retry -->|"是"| Wait
    Retry -->|"否"| Fail["丢弃帧,上报错误 ❌"]

    style Done fill:#98FB98,color:#000
    style Fail fill:#FF6B6B,color:#fff

四个步骤详解

步骤 英文名称 说明
1 Carrier Sense 发送前先监听:信道忙就等,空闲才发
2 Multiple Access 多个设备共享同一介质
3 Collision Detection 发送过程中持续监测是否有冲突信号
4 Collision Handling 检测到冲突 → 发 Jam Signal → 执行退避 → 重试

Slot Time(时隙)

在讲解退避算法之前,先认识一个核心概念——Slot Time(时隙/争用期):

\text{Slot Time} = 512 \text{ bit-time} = 51.2 \mu s \quad (\text{在 10Mbps 以太网下})

时隙是 CSMA/CD 中所有时间计算的基本单位,它的值约等于最大往返传播延迟(~46.4μs)+ Jam Signal 时间(~3.2μs)+ 安全余量。退避算法中的等待时间、最小帧长、冲突检测窗口,全部以它为基准。

[!QUESTION] 为什么 Slot Time 要比理论往返延迟长一点? 因为检测到冲突后还需要发送 Jam Signal 确保所有节点都感知到碰撞。如果时隙刚好等于往返延迟,发送方在时隙结束时还没完成 Jam Signal 的发送,就可能误以为"没冲突"。

Jam Signal(强化冲突信号)

检测到冲突后,发送方会立刻发出一个 32 bit 的 Jam Signal,目的有二:

  1. 强化冲突:确保网络上所有节点(包括距冲突点较远的节点)都能检测到碰撞
  2. 延长冲突持续时间:使冲突信号维持足够长的时间,避免有节点"刚好错过"碰撞窗口

Jam Signal 的传输时间约 3.2μs(10Mbps),已包含在 Slot Time 的计算中。

二进制指数退避算法

冲突后的等待时间通过随机退避来避免再次碰撞——选到相同随机数的概率随窗口增大而降低:

\text{backoff} = r \times \text{Slot Time},\quad r \in \{0, 1, \ldots, \min(2^k - 1, 1023)\}

其中 k 为该帧的重传次数。每次冲突后窗口翻倍(指数增长),上限固定在 1023。

flowchart TD
    k["重传次数 k"] --> window["窗口大小 min(2^k - 1, 1023)"]
    window --> r["r = random(0 ~ 窗口大小)"]
    r --> backoff["backoff = r × 51.2μs"]
    
    style k fill:#DDA0DD,color:#000
    style backoff fill:#98FB98,color:#000

退避表

重传次数 k 窗口大小 min(2^k - 1, 1023) r 的取值范围 最大等待时间
1 1 {0, 1} 51.2μs
2 3 {0..3} 153.6μs
3 7 {0..7} 358.4μs
4 15 {0..15} 768μs
5–10 2^k - 1 → 1023 {0..1023} 52.4ms
>10 1023(上限固定) {0..1023} 52.4ms

[!tip] 为什么窗口要"封顶"在 1023? 如果不封顶,k=16 时窗口可达 65535,等待时间超过 3 秒——太久了。封顶保证了最坏情况下的重传延迟有上界,同时也意味着高冲突率下不同节点的退避选择可能重复,这就是网络严重拥塞时的"公平性代价"。

如果重传 16 次仍然失败,帧被丢弃并向上层报告错误。

示例

假设节点 A 和 B 同时发送,发生冲突:

时刻 0μs:     A 和 B 同时开始发送
时刻 23.2μs:  A 检测到冲突(假设距冲突点约 23.2μs)
              A 和 B 均发送 Jam Signal (32bit, 约 3.2μs)
              此时 Slot Time 计时仍在继续...
时刻 51.2μs:  Slot Time 结束,进入退避期
              A 选 r=3 → 等 3 × 51.2μs = 153.6μs
              B 选 r=1 → 等 1 × 51.2μs = 51.2μs
时刻 102.4μs: B 先等完 → 检测信道空闲 → 发送 ✅
时刻 204.8μs: A 等完 → 检测信道忙碌 → 等待...
              (A 的本次重传计数 k=2,下次窗口扩大为 {0..3})

[!QUESTION] 第二次冲突时,A 和 B 还是同时选到相同 r 怎么办? 第二次冲突时窗口翻倍到 {0..3},选到相同值的概率从 1/2 降到 1/4。指数退避的核心思想就是:冲突越频繁,等待范围越大,再次碰撞的概率越低。当然,极端情况下仍可能连续冲突——这就是为什么 16 次后要放弃。

最小帧长与争用期

为什么最小帧是 64 字节?

核心原则:帧传输时间 ≥ 往返传播延迟

如果帧太短,发送方可能在冲突信号返回之前就已经发完了——根本不知道发生过冲突,也就无法重传。

sequenceDiagram
    participant A as "节点 A"
    participant H as "最远节点 H"
    Note over A,H: "传播延迟 τ"
    
    A->>H: "发送一个超短帧 (长度 < 2τ)"
    H->>A: "冲突信号返回"
    Note over A: "此时 A 已经发完了...<br/>没检测到冲突!"

所以必须满足:

\text{最小帧长} \geq 2 \times \tau_{\max} \times \text{带宽}

其中 \tau_{\max} 是网络中最远两个节点之间的单程传播延迟。

从理论推导到工程标准

对于经典 10Mbps 以太网(10BASE5 粗缆 + 4 个中继器,总跨度约 2500m):

\tau_{\max} \approx 46.4\mu s \quad \text{(含中继器延迟)}

代入公式:

\text{最小帧长} \geq 46.4\mu s \times 10^7 \text{ bps} \approx 464 \text{ bits}

IEEE 在此基础上统一向上取整,取了一个干净的 2 的幂次方——512 bits(64 bytes),这也是 Slot Time 的值。多出的 48 bits 作为安全余量,同时覆盖了 Jam Signal 的传输时间。

[!tip] 帧长与 Slot Time 的关系 最小帧长 = Slot Time × 带宽 = 512 bit-time × 1 bps = 512 bits = 64 bytes

这不是巧合——最小帧长的设计保证了:只要帧还在传输中(长度 ≥ Slot Time),冲突就一定能被检测到。退避算法以 Slot Time 为单位,最小帧长以 Slot Time 为下限,二者在设计上是统一的。

碰撞域(Collision Domain)

理解 CSMA/CD 就不得不理解碰撞域——所有共享同一冲突检测范围的节点组成一个碰撞域:

graph LR
    subgraph CD1["碰撞域 1 (Hub 连接)"]
        A["节点 A"] --- Hub["Hub 集线器"]
        B["节点 B"] --- Hub
        C["节点 C"] --- Hub
    end
    Switch["交换机"] --- Hub
    Switch --- D["节点 D"]
    Switch --- E["节点 E"]
    subgraph CD2["碰撞域 2"]
        D
        E
    end

    style CD1 fill:#FFE4E1,stroke:#FF6B6B,stroke-width:2px
    style CD2 fill:#E1F5FE,stroke:#4FC3F7,stroke-width:2px
  • Hub:不隔离碰撞域——所有连接到同一 Hub 的设备属于同一个碰撞域
  • Switch:每个端口是一个独立碰撞域,从根本上消除了 CSMA/CD 的需求
  • 广播域则不同,由 VLAN 划分,和 CSMA/CD 无关(详见 05-VLAN与Trunk)

半双工 vs 全双工

CSMA/CD 的"监听-发送-检测-退避"机制本质上是半双工的——同一时间只能收或发,不能同时进行。全双工模式通过物理上分离收发通道彻底绕开了这个问题:

模式 通道 冲突 CSMA/CD 典型场景
半双工 (Hub) 共享 存在 必需 早期总线/Hub 网络
全双工 (Switch) 收发分离 不存在 自动关闭 现代交换网络

从 Gigabit Ethernet (802.3ab) 起,交换机端口默认全双工运行。虽然标准中仍保留了半双工 CSMA/CD 定义(用于兼容),但实际网络中已几乎不再使用。

graph LR
    subgraph HalfDuplex["半双工 (Hub)"]
        direction LR
        H1["节点"] -- "发送" --> H2["Hub"]
        H2 -- "接收" --> H1
    end
    subgraph FullDuplex["全双工 (Switch)"]
        direction LR
        S1["节点"] -- "发送" --> S2["Switch"]
        S2 -- "接收" --> S1
    end

    style HalfDuplex fill:#FFF3E0,stroke:#FF9800
    style FullDuplex fill:#E8F5E9,stroke:#4CAF50

[!note] 半双工 vs 全双工的本质区别

  • 半双工:收发共用一条通道,同一时刻只能单向通信,需要 CSMA/CD 协调
  • 全双工:收发各有独立通道(物理上两对线),可同时双向通信,CSMA/CD 自动关闭

[!note] 如何检查当前网卡是否启用了 CSMA/CD?

$ ethtool eth0 | grep -i coll
Supports Collision Detection: yes
Current Collision Detection: disabled (full-duplex)

现代网卡通常显示 "disabled (full-duplex)",说明 CSMA/CD 已关闭。

关联笔记