资讯动态

从CSMA/CD到CSMA/CA:介质访问控制原理与排障实战

发布时间:2026/10/26 12:57:20 来源:尧图企业网站定制
聊数据链路层多数人第一反应是帧格式、MAC 地址、CRC 校验这三件套翻到介质访问控制那一节往往草草带过考试前背两句 CSMA/CD 就结束了。可真到了现场问题往往就出在这块被跳过的内容上共享链路上两个设备一抢就把吞吐打到谷底半双工端口对不上导致传大文件像挤牙膏无线侧几个终端互相“听不见”却都以为信道空闲。介质访问控制MACMedium Access Control说白了就是一套“谁先说话”的仲裁规则用来决定一根线、一段频率、一片空口被多个使用者共享时谁在什么时刻拥有发送权。它解决的是共享介质上的争用与冲突问题直接影响链路利用率、时延确定性和故障表现。我写这篇的目标读者有三类正在啃数据链路层、想把“为什么是 64 字节”“为什么无线不能边发边听”搞明白的同学天天和交换机、无线 AP 打交道看到 collisions、late collision、retry 这些计数器却不确定该不该管的运维以及写底层通信代码、需要判断重传时序和退避窗口是否合理的工程师。下面我会把仲裁机制的原理、参数背后的推导、能直接照着跑的计算和模拟、以及几个真金白银换来的排查经验一条条摆出来。1. 介质访问控制到底在管什么1.1 从一间只有一支话筒的会议室说起共享式以太网早期用同轴电缆做总线所有站点都并联在同一根物理介质上。这根线上的电平是所有人信号的叠加一旦两个站点同时发送叠加出来的波形对接收方来说就是无意义的噪声谁也还原不出原始比特这就是冲突。冲突域指的就是同一时刻只允许一个站点发送的物理范围。介质访问控制要处理的正是这个窘境没有中心调度者各站点只能靠一套约定俗成的规则自行协商发送时机。规则设计得好大家相安无事设计得差一起抢就一起完蛋。这就像一间只有一支话筒的会议室没人主持只能靠“先听一下有没有人在说、说之前举下手、撞上了就各自停一会儿再说”的默契。默契的细节差异构成了后面几十年的技术演化路线。理解这一点很关键因为很多现场问题的根因不在协议栈上层而在这条“默契”规则被破坏或者不适用。比如把半双工设备塞进本该全双工的链路两边遵循的仲裁规则根本对不上冲突检测机制的假设直接失效。1.2 LLC 与 MAC 的分工以及为什么要拆成两层早期的链路层参考模型把它拆成两个子层。上层是逻辑链路控制LLC负责和网络层对接做协议复用与解复用、提供差错与流量控制的统一接口下层是介质访问控制MAC负责组帧、编址、帧校验序列的生成与校验以及最核心的信道仲裁。为什么要把仲裁单独下沉一层因为仲裁规则和物理介质强绑定。同轴总线需要冲突检测无线空口只能靠确认令牌环则需要一个环形的令牌传递顺序这些差异全部封在 MAC 子层里上层的 LLC 就可以保持不变。这和我后来做跨平台适配时的思路一样把平台相关的脏活压在薄薄一层里上面的业务逻辑尽量不动。在今天的以太网实现里LLC 那套复用功能已经退化成帧头里的类型字段两层在网卡固件里基本合并了。但概念上的拆分仍然成立你去看 802 系列标准仲裁相关内容始终写在 MAC 子层这不是历史包袱而是职责边界划得干净。1.3 三类信道场景与两套解法按使用方式区分链路上的信道大致有三类对应的仲裁需求完全不同。第一类是点对点链路两端之间只有彼此谁发谁收没有歧义根本不需要仲裁规则帧格式里也就没有地址字段的必要性。第二类是共享广播介质多个站点挂在一起这是仲裁规则的主战场早期总线以太网、无线局域网、同轴电缆接入都属于这一类。第三类是交换式链路每个端口自成一个冲突域全双工下收与发各走独立通道冲突从物理上就不存在了。针对共享介质行业里演化出两条完全不同的技术路线。第一条是随机访问谁想发谁就抢撞了再退好处是低负载时几乎无开销、实现简单坏处是高负载时冲突频发、时延没有上界。第二条是受控访问或者信道划分要么按顺序发令牌、轮询要么把信道静态切成频段、时隙或码型分给各站好处是有确定性、重负载下效率高坏处是需要额外的调度开销、轻负载时资源浪费。下面这张表是我习惯用来快速对比的速查表记住这张表绝大多数场景该选哪条路就有数了。方案类型典型代表低负载表现高负载表现时延确定性实现复杂度随机访问ALOHA、CSMA、CSMA/CD、CSMA/CA优秀几乎无额外开销依赖退避算法效率下降无上界低受控访问令牌环、令牌总线、主从轮询较差空转等待令牌或轮询接近饱和效率高有上界中到高信道划分频分、时分、码分差时隙或频段空置即浪费稳定各站互不干扰固定中需同步2. 随机访问的演化路径与参数推导2.1 ALOHA 的朴素与分槽带来的翻倍最早的随机访问方案来自早期的无线分组网络思路直白到有些粗暴有帧就发发完等确认超时没等到就随机等一段时间重发。假设单位时间内产生的总发送尝试服从泊松分布经过推导纯 ALOHA 的信道吞吐率在负载为 0.5 时取到峰值 18.4%也就是 100% 的带宽里最多只有不到两成真正传了有效数据其余全被碰撞浪费掉了。改进办法很聪明给时间划上刻痕所有站点只能在时隙的起始点开始发送。这样一来一帧的易受碰撞窗口从两倍帧时缩短为一倍帧时吞吐率峰值直接翻到 36.8%。这不到两倍的提升带来一个很实用的启示把随机行为约束在离散时刻上能显著减少重叠区间的长度。这个思想后来在 CSMA 的时隙退避里一直沿用。为什么还要讲这段历史因为它确立了随机访问的范式骨架即自由竞争、冲突后退避重试后面所有方案都是在“什么时候可以尝试”和“撞了之后等多久”这两点上做加法。抓住这个骨架CSMA 家族的演进就不需要死记硬背了。2.2 CSMA 的三种坚持方式以及冲突检测为何值钱CSMA 的核心动作只有一个先听后说。发送前先监听介质忙就不发空闲再发。判断要发的时候怎么做衍生出三种版本。1-坚持策略是信道一空闲就立刻发实现最简单代价是多个等待中的站点会同时探到空闲一起发必然撞车冲突概率最高。非坚持策略是信道忙就随机等一段再重新听冲突明显减少问题是有时候没人发、信道却空着利用率下降。p-坚持策略针对时隙信道空闲时以概率 p 发送、以 1-p 推迟到下一个时隙相当于在前两者之间找平衡p 的取值需要根据站点数整定。光靠先听后说还不够。假设两个站点几乎同时探到空闲并同时开始发冲突已经产生了如果它们坚持把整个帧发完才发现那整段时间全浪费。冲突检测就是在这里加码发送过程中继续监听介质一旦发现自己的信号与接收到的信号不一致立刻停止发送并发送一个短促的强化冲突信号让附近所有站点都确认发生了冲突然后各自进入退避。这一步的收益极其可观。一个 1500 字节的帧在 10Mbps 上要传 1.2 毫秒如果冲突在帧刚开始的头几微秒就能确定剩下的时间全部省下来了。CSMA/CD 的效率优势主要来自这里而不是先听后说本身。2.3 二进制指数退避为什么不能线性等待冲突发生后各站必须错开时间重试否则会立刻再次撞上。最直观的想法是“第几次冲突就等几倍时间”即线性退避。问题在于冲突次数相同的站点等待时间几乎重合实际参与竞争的站点数并没有被摊薄高负载下会出现连续的重复冲突系统吞吐断崖式下跌。截断二进制指数退避换了个思路第 i 次冲突后从 0 到 2^k 减 1 的范围里随机挑一个整数作为退避时隙数其中 k 取 i 与 10 之间的较小值。也就是说第一次冲突只等 0 或 1 个争用期第二次等 0 到 3 个第三次等 0 到 7 个范围随冲突次数指数放大到第十次之后固定在 0 到 1023 个争用期。连续冲突达到 16 次仍不成功就丢弃该帧并向上一层报告。这里的设计意图值得掰开讲。指数放大让重试的时间窗口迅速拉开参与竞争的站点被“摊”到一个越来越宽的区间上同时重试的概率随之下降冲突的收敛速度快得多。而 10 次之后停止放大是为了防止窗口无限增长导致等待时间失控毕竟退避窗口不能大到一个帧等上几十毫秒还没机会发。该类方案最坏情况下的重传时延没有上界这也是后来工业场景更偏爱确定性方案的原因。注意二进制指数退避的“指数”只作用在随机窗口的宽度上不是等待时间本身。实际等待时长 随机时隙数 × 争用期所以退避范围虽然指数增长单次 waits 的期望值只是乘上了一个随冲突次数增长的系数。2.4 争用期与 64 字节最小帧长的完整推导这是整个数据链路层最值得动手算一遍的地方因为几乎每一道相关考题和每一次现场困惑都绕不开它。冲突检测的可行性建立在一个时间约束上发送方必须在“自己的信号已经传遍全网”之前持续监听才能捕捉到可能发生的冲突。考虑最坏的场景发送方 A 位于链路一端接收方 B 位于另一端单程传播时延为 τ。A 的信号传到 B 需要 τB 若在此之前已经开始发送冲突会在 B 附近产生冲突信号再传回 A 又需要 τ。因此 A 最多需要 2τ 的时间才能确认“是否发生冲突”。这段时间被称为争用期或者冲突窗口。如果 A 的整个帧发送时间 T0 小于 2τ那么在冲突信号回来之前 A 已经把帧发完了它会误认为发送成功、释放信道而此时网络上实际已经乱了。所以帧的发送时间必须不短于争用期等价地帧长必须不小于 2τ 乘以信道带宽。这就是最小帧长的来历。经典参数可以完整算出来。10Mbps 共享式以太网标准按最坏拓扑估算五段电缆、四个中继器、总线总长约 2500 米信号在电缆中的传播速度约每秒两亿米单程传播时延约 12.5 微秒。但仅仅 25 微秒的往返还不够中继器和收发器本身会引入额外延迟标准把这些折算进去之后把争用期定为 512 比特时间在 10Mbps 下就是 51.2 微秒等效往返距离约一万米远大于 2500 米的实际线缆长度。于是最小帧长 51.2 微秒 × 10Mbps 512 比特 64 字节。这 64 字节包含目的地址 6 字节、源地址 6 字节、类型字段 2 字节、帧校验序列 4 字节剩下的数据字段最少 46 字节。帧不够长怎么办上层补齐也就是填充字段的由来。这个推导反过来能解释很多限制。假如把网络直径扩大到 6 公里2τ 约 60 微秒乘以 10Mbps 得到 600 比特超过了 512 比特的帧长冲突检测就不可靠了所以早期以太网对网络直径有硬性约束。同样的逻辑搬到千兆速率上速率提高十倍同样 64 字节的帧只够覆盖十分之一的距离。半双工千兆为此引入了载波扩展把实际发送时间补足到 512 字节时间还有帧突发机制让多个短帧连发时只补一次。常见的说法“千兆半双工网络直径只有几百米”源头就在这里。2.5 CSMA/CA无线为什么不能边发边听无线局域网没法照搬冲突检测原因有两层第二层更致命。第一层是物理实现的困难。无线收发共用天线发射功率通常远高于接收到的对方信号自己的发射信号会把接收前端淹没动态范围不足以在发送的同时分辨出“别人是不是也在发”。有线总线时代可以做电压比较来判断冲突无线里这条路基本走不通。第二层是隐藏终端问题。A 和 C 都在 B 的覆盖范围内但 A 与 C 之间因为距离或者遮挡互相听不到。A 和 C 都监听信道都探到空闲于是同时向 B 发送冲突在 B 处发生。冲突检测对此无能为力因为冲突根本不在发送方那里发生。这就是无线必须引入预约机制的原因。CSMA/CA 的做法是把“检测”换成“避免”。发送前先遵循帧间间隔规则再启动随机退避计数信道空闲则计数递减信道忙则冻结计数等待计数归零才发送。帧间间隔分了等级短间隔最短用于确认帧和控制帧保证它们优先获得信道普通数据帧则要等更长的分布式帧间间隔。这个设计让不同优先级的帧有了天然的排队次序。解决隐藏终端靠的是短控制帧的握手预约发送方先发一个请求发送帧接收方回一个允许发送帧两者都携带预约时长。附近能听到这次握手的站点据此更新自己的网络分配向量在预约时长内保持静默这就是虚拟载波监听。没听到握手但实际会干扰的站点则靠这次的物理监听加上后续的确认帧重传来兜底。最后无线没有冲突检测发送成功与否只能靠接收方回确认帧来推断。收到确认才算送达超时未收到就认为失败并扩大退避窗口重试连续失败若干次后速率和窗口都会调整。这套机制让无线的行为模式和有线的“发出去就大概成了”截然不同别拿有线的直觉去解释无线的吞吐抖动。顺便说一个实操中容易混淆的点握手机制虽然能缓解隐藏终端但不是无脑开就好。请求发送帧本身是固定开销帧很短的时候握手成本相对占比过高反而降低吞吐所以实际设备都会设置一个帧长阈值超过阈值才启用握手。我见过有人为了“优化”把阈值调到最小结果短包业务性能明显变差。3. 受控访问与信道划分这条路线3.1 令牌传递把随机性换成确定性令牌环的思路是让一个特殊格式的令牌帧沿着环单向传递只有持有令牌的站点才被允许发送数据发完或者达到令牌持有时间上限就释放令牌给下一站。这样任何时刻环上最多只有一个站在发冲突从规则上被消除了。它换来的是确定性。每个站点等待令牌的最坏时间是可以算出来的等于环上所有站的令牌持有时间之和加上传播时延这对工业控制、车载、早期语音这类对时延上限敏感的场景非常有吸引力。重负载时环几乎一直在传数据效率逼近百分之百这也解释了为什么当年在重载环境下它能和以太网分庭抗礼。代价同样明显。轻负载时明明只有一个站有数据要发它还得老老实实等令牌绕一圈回来时延白白增加。可靠性上令牌可能因为干扰而丢失也可能因为故障站重复发送而出现多个令牌所以环上必须有站点承担监控职责负责令牌的恢复与环的插入拆除。再加上单点故障的敏感性和设备成本交换式全双工以太网普及之后这条路线基本退出了主流局域网市场只在部分工业现场总线和特定嵌入式场景里保留了类似思想。3.2 轮询与信道划分谁更省谁的资源轮询是主从结构的经典做法主站依次向从站发问询帧从站有数据就发没数据就回一个空响应或者干脆不回。整个过程无冲突实现也简单特别适合上行下行不对称、终端数量可控的接入场景比如早期的集中式无线接入和不少工业现场总线。代价是轮询开销随从站数量线性增长而且主站一旦失效整个系统就停摆。信道划分是另一条思路把共享介质按照频率、时间或者码型切分开每个站固定占一份物理上互不干扰。频分把总带宽切成若干互不重叠的子频段每个站独占一段实现简单代价是需要保护间隔而且某个站没数据时那段频率就闲置。时分把时间切成周期性的帧每帧里给每个站分配固定时隙同步要求高同样存在空闲浪费。码分则允许所有站同时同频发送靠互相正交的码型在接收端分离抗干扰能力强但码片速率要求高、功率控制复杂。这三类划分的共同软肋是静态。业务流量几乎从不均匀某个站满载、其他站空闲时静态划分的资源利用率非常难看。所以现代系统基本都走混合路线底层用信道划分保证隔离上层再叠加按需分配的逻辑。3.3 交换式全双工之后冲突检测还剩什么交换机把每个端口变成独立冲突域全双工下收发走不同的线对或者不同的波长物理上不存在同时发送导致的叠加冲突检测自然失去了用武之地端口上的该机制会被关闭。但这并不意味着学它没用恰恰相反实际排障里它的“残留痕迹”价值极高。很多网卡的统计计数器里依然保留着冲突相关的项这些数字在正常全双工链路上应该恒为零。一旦出现增长说明链路上有一端还停留在半双工模式遵循着老规则在检测冲突并退避重传而全双工的另一端完全不知情这种不对称就是后面要讲的“能通但极慢”故障的典型成因。另外早期集线器把多个端口物理上连成同一个冲突域那种设备的端口计数器上看到冲突是正常的。现在还能在部分老旧现场看到集线器一旦看到冲突计数持续增长别急着怀疑网卡先确认是不是还有共享设备串在链路里。4. 动手把参数算一遍、把退避跑一遍4.1 三个必算的参数与结果解读第一个是争用期。已知单程传播时延 τ争用期就是 2τ。以一段一公里、信号速度每秒两亿米的链路为例τ 1000 / 2e8 5 微秒争用期 10 微秒。在 10Mbps 下10 微秒能传 100 比特也就是说这段链路上最小帧长只要 100 比特远小于标准的 512 比特余量充足。第二个是最小帧长。反过来用链路最长 5 公里时2τ 50 微秒10Mbps 下需要 500 比特接近 512 比特的边界。若再拉长到 6 公里2τ 60 微秒需要 600 比特标准帧长就不够了。所以早期标准的直径限制不是拍脑袋定的。第三个是链路效率。常用近似式为效率约等于 1 除以 1 加 5a其中 a 定义为单程传播时延除以帧传输时间。还是上面一公里的例子帧长 512 比特在 10Mbps 下传输时间 51.2 微秒a 5 / 51.2 ≈ 0.098效率约等于 1 / 1.49 ≈ 0.67。这个数字说明在这么大的网络上理论峰值只有六成多能用来传有效载荷剩下的都被仲裁和传播开销吃掉了。把帧长加大到 1500 字节传输时间升到 1.2 毫秒a 降到 0.004效率跳到 0.98 以上这也解释了为什么大帧传输的吞吐总是明显好于小包。千兆半双工的约束也能顺手算出来。载波扩展把最小发送时间拉到 512 字节时间也就是 4096 比特1Gbps 下是 4.096 微秒它对应往返时延单程 2.048 微秒乘以每秒两亿米得到约 410 米。这就是千兆半双工网络直径的量级。4.2 用一段脚本把二进制指数退避跑起来光看公式没感觉我一般用几行代码把退避过程模拟一遍看窗口分布和收敛速度。import random SLOT_US 51.2 # 10Mbps 以太网的争用期单位微秒 def backoff_slots(attempt): 第 attempt 次冲突后的退避时隙数attempt 从 1 开始 k min(attempt, 10) return random.randint(0, 2 ** k - 1) print(冲突次数 窗口上限 本次时隙 等待(us)) for i in range(1, 17): slots backoff_slots(i) print(f{i:8} {2 ** min(i, 10) - 1:8} {slots:8} {slots * SLOT_US:8.1f})跑出来的前几行会看到第一次冲突只等 0 或 51.2 微秒第二次最多 153.6 微秒第三次最多 358.4 微秒到第十次窗口上限达到 1023 个时隙也就是最长五十多毫秒。第十六次仍失败就该向上层报错了。再往下一步可以模拟多个站点同时争抢统计冲突率和吞吐直观感受指数退避和线性退避的差距。核心是把每个站点的重传次数作为状态带着走每轮让所有待发站点各自抽一个退避时隙抽到最小时隙的那个站成功发送其他站的等待计数扣减相应值扣到零且没能抢到的计入一次冲突并重新抽取。心得模拟时别忘记“信道忙则冻结计数”这个规则。我第一版漏掉了冻结逻辑导致负载一高所有站点的计数永远同时归零算出来的冲突率明显偏高白折腾了半天。4.3 从网卡计数器里读出冲突与重传的痕迹故障现场没有模拟器可用只能靠计数器说话。下面几条是我最常用的入口。# 查看接口总体收发包与错误统计 ip -s link show eth0 # 查看驱动层更细的计数器 ethtool -S eth0 | grep -iE collision|fcs|crc|drop|error|late读法很直接。collisions 在半双工端口上正常增长在全双工端口上应该恒定为零如果全双工端口上出现了 late collision 或者类似含义的迟到冲突计数几乎可以直接判定双工不匹配或者线缆过长冲突信号回得太晚超出了检测窗口。FCS、CRC 类错误的增长指向物理层问题比如线序、干扰、接触不良和仲裁无关别混在一起查。无线侧没有冲突计数器但重传计数可以看# 查看无线接口上的重传与失败统计需要相应工具支持 iw dev wlan0 link iw dev wlan0 station dump | grep -iE retry|fail|tx重传比例持续偏高通常意味着空口竞争激烈、信号质量差或者存在隐藏终端干扰。这时候先看信道占用率和相邻干扰再去调握手的帧长阈值顺序反过来往往越调越乱。5. 常见问题与排查实录5.1 一张速查表覆盖八成现场现象优先怀疑的仲裁问题验证手段处理方向能 ping 通但大文件极慢双工模式不匹配一端检测冲突重传两端看双工配置与 late collision 计数强制统一双工与速率或都开自协商全双工端口冲突计数增长存在共享设备或强制半双工遗留查拓扑是否有集线器查端口配置移除共享设备统一为全双工小包吞吐差、大包正常帧长短导致固定开销占比高冲突窗口相对变大算 a 值与理论效率合并小包调整应用侧批量策略无线人多就掉速严重空口竞争加剧隐藏终端导致退避频繁看重传比例与信道占用调整发送功率与信道必要时启用握手阈值重载时延抖动极大随机访问方案本身的时延无上界长时间统计时延分布关键业务改走确定性调度方案千兆半双工链路距离受限争用期与最小帧长的约束核算 2τ 与载波扩展时间改全双工或缩短链路5.2 三个我反复遇见的坑第一个是双工不匹配。表现极具迷惑性链路状态是 upping 通小文件传输正常一传大文件速度断崖式下跌有时还伴随间歇性丢包。原因是一端被强制成全双工另一端还是半双工。半双工端遵守老规则边发边听发现冲突就退避重发全双工端没有冲突概念收到就收、发完就忘。半双工端反复重传还没等到确认上层就表现为超时。这种不对称还会让链路利用率看起来很低因为半双工端一直在退避。处理办法是把两端都恢复自协商或者都强制成同一模式千万别一端强制一端自协商。第二个是把无线当有线查。有人看到无线吞吐抖动第一反应是带宽不够或者设备性能差一头扎进设备侧。实际上空口共享的本质决定了它天然存在竞争抖动客户端一多退避和重传必然上去。这时候该做的是测信道占用、看重传比例、调整功率和信道规划而不是加带宽。我在一个密集部署的办公区见过单台设备性能没问题整体体验差根因是同频相邻干扰导致空口竞争失控降功率、拉开信道反而好转。第三个是抓包位置选错去找冲突。交换机端口本身是独立冲突域在镜像口上永远抓不到冲突冲突只发生在共享介质或者半双工链路上。想确认冲突相关问题得看计数器和链路配置或者把抓包点放在真正的共享段上。这个坑我踩过不止一次浪费时间在没有答案的地方。提醒涉及端口模式强制、握手阈值这类参数的调整务必先记录原配置并准备回滚方案。这类参数改动带来的影响往往要过一段时间才显现出问题时如果连改过什么都记不清排查成本会成倍上升。最后分享一点个人体会。介质访问控制这部分内容教材上讲得抽象是因为它本来就是为了解决一个很具体的物理困境而生的规则集合。我后来养成一个习惯每看到一个仲裁参数就回头问一句“它是在防哪种最坏情况”争用期防的是最远端冲突回不来最小帧长防的是发完了才发现撞了指数退避防的是重试扎堆帧间间隔防的是确认帧被数据帧挤掉。把这几个“防什么”记住参数是怎么来的、什么时候会失效心里自然有底排查时也不会在无关的计数器上兜圈子。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑