☰
IEEE 802.11协议精讲:从DCF机制到Bianchi模型与抓包调试实战
2026/9/26 1:22:11 网站建设 项目流程

简介:这份文档面向无线网络初学者、网络工程师及备考认证的技术人员,系统梳理IEEE 802.11协议族的核心知识,帮助读者理解Wi-Fi从802.11a/b/g到802.11n的演进脉络与底层通信机制。资源为单个docx文件,压缩包约12.07MB,内容以图文笔记形式组织,涵盖Wi-Fi起源与发展、DCF与CSMA/CA机制、BEB二进制指数退避、RTS/CTS模式、物理与虚拟载波监听、能量检测与载波侦听,以及DIFS、SIFS与Slot time等关键时序参数,并对比CSMA/CD与CSMA/CA的差异。目录结构按协议精读章节递进,便于按主题查阅与培训讲解。目前已有144人学习下载,适合作为内部培训教材或自学参考资料,帮助读者建立从信道竞争到冲突避免的完整认知框架,为无线网络调试与优化打下基础。

1. 一份把 802.11 从帧结构讲到 Bianchi 模型的培训文档,到底值不值得啃

做无线抓包分析的人大概都经历过这种场景:Wireshark 里抓了一堆 802.11 管理帧和数据帧,Retry 标志位频繁置位,但就是说不清是信道竞争导致的退避重传,还是隐藏终端引发的碰撞。想翻协议原文,IEEE 802.11-2020 标准文档上千页,光 DCF 那一章就够看三天。这时候如果手头有一份按主题拆好、带时序图和公式推导的中文整理文档,效率完全不一样。

这份《IEEE 802.11 协议资料整理》就是干这个的。它把 802.11 协议族从 Wi-Fi 起源、DCF/CSMA/CA 机制、PCF 工作模式、隐藏/暴露终端问题,一路讲到 802.11a/b/g 的物理层收发过程、节能模式(PSM/APSD/PSMP/SMPS)、物理层速率计算、Bianchi 模型理论性能分析、链路模型与信道模型。适合无线网络工程师、嵌入式 Wi-Fi 驱动开发者、以及准备做 WLAN 性能仿真验证的研究人员。关键词 LBT、CSMA/CA、RSSI、802.11a/b/g/n 在文档里都有对应章节展开,不是泛泛而谈的概念科普。

2. 从 DCF 到物理层收发:文档的知识骨架怎么搭

2.1 为什么先啃 DCF 和 CSMA/CA 这两块硬骨头

802.11 协议最核心的 MAC 层机制就是 DCF(分布式协调功能),而 DCF 的底层依赖 CSMA/CA。文档把这两块放在最前面讲,顺序是对的。如果连信道竞争的基本流程都没搞明白,后面看节能模式里的 TIM 帧和 Listen Interval 就是空中楼阁。

CSMA/CA 的工作流程文档拆成了四步:监听、退避、发送、确认。每一步都有对应的时序图描述。比如信道从忙变闲之后,站不能立刻发,必须等一个 DIFS(DCF Interframe Space)才能进入退避窗口。这个 DIFS 的长度是 SIFS 加上两个 Slot time。文档里给了具体的数值关系,2.4GHz 频段下 SIFS 是 10μs,Slot time 是 20μs,所以 DIFS 就是 50μs。这些数字在调驱动参数的时候经常用到。

退避机制用的是 BEB(二进制指数退避)。第一次退避从 [0, CW_min] 里随机取一个值,CW_min 通常是 15。每次碰撞后 CW 翻倍再加一,直到 CW_max(通常是 1023)。文档里把 BEB 的伪代码逻辑画出来了,理解起来比看标准原文快很多。

RTS/CTS 模式是 CSMA/CA 的可选增强。文档解释了什么时候该开 RTS/CTS 阈值——不是所有场景都适合开。小包频繁发送的场景下,RTS/CTS 的额外开销反而会拉低吞吐量。一般建议在帧长超过 RTS_Threshold 时才启用,这个阈值默认是 2347 字节,实际部署时可以根据环境调整。

物理载波监听和虚拟载波监听是两条并行的判断逻辑。物理载波监听靠 CCA(空闲信道评估),CCA 又分能量检测和载波侦听两种方式。能量检测看的是 RSSI 是否超过阈值(通常 -62dBm 到 -82dBm 之间),载波侦听看的是能不能解出前导码。虚拟载波监听靠的是 NAV(网络分配矢量),从 RTS/CTS/ACK 帧的 Duration 字段里提取信道占用时间。文档把这两条线的交互关系讲清楚了,这是很多只讲概念的教程会跳过的地方。

2.2 物理层收发过程:802.11b 和 802.11a/g 的差异在哪

文档从第 6 章开始进入物理层。802.11b 用的是 DSSS/CCK 调制,物理层头部包含 PLCP Preamble 和 PLCP Header。Preamble 分长前导和短前导两种,长前导 144bit,短前导 72bit。短前导能降低开销但兼容性差一些。文档把发送过程和接收过程的每一步都列出来了,包括 scrambling、convolutional encoding、interleaving 这些细节。

802.11a/g 用的是 OFDM。文档第 8 章专门讲了 OFDM Symbol 和 Subcarrier 的时域/频域结构。一个 OFDM Symbol 的持续时间是 4μs,其中 0.8μs 是 Guard Interval,3.2μs 是有效数据部分。子载波间隔是 312.5kHz,20MHz 带宽下有 64 个子载波,其中 48 个用于数据传输,4 个导频,剩下的做保护带。这些参数直接决定了物理层速率怎么算。

物理层速率计算这块,文档给了完整的推导。以 802.11a/g 为例,20MHz 带宽、64-QAM 调制、编码率 3/4 的情况下,每个子载波承载 6bit,48 个数据子载波就是 288bit,除以 4μs 的符号周期,得到 72Mbps。再乘以编码率 3/4,就是 54Mbps。这个计算过程文档里写得很清楚,比直接背速率表有用得多。

2.3 节能模式和性能分析:从 PSM 到 Bianchi 模型

节能模式这块文档花了三章来讲。基础 PSM 的核心思想是站进入睡眠状态,AP 缓存下行数据,通过 Beacon 帧里的 TIM 字段通知站有数据待取。TIM 里的 Bitmap 每个 bit 对应一个关联站的 AID,站醒来后看自己的 bit 是否置位,置位就发 PS-Poll 帧取数据。

文档把 AID、TIM、Bitmap、TSF、TBTT、Listen Interval 这些概念串起来了。Listen Interval 是站告诉 AP 自己多久醒一次,单位是 Beacon 间隔。这个值设大了省电但延迟高,设小了省电效果差。实际调优时需要在功耗和延迟之间找平衡点。

进阶节能模式 APSD、PSMP、SMPS 文档也覆盖了。APSD 分 U-APSD 和 S-APSD,U-APSD 允许站通过触发帧一次性取多个缓存帧,减少 PS-Poll 的开销。PSMP 是 AP 集中调度站的收发时间,适合高密度场景。SMPS 是空间复用节能,跟 MIMO 天线数相关。

Bianchi 模型是分析 DCF 性能的经典理论模型。文档第 13 章给出了模型的假设条件、归一化吞吐量公式、传输概率和冲突概率的推导。核心思路是把每个站的退避过程建模成马尔可夫链,求出稳态下站在任意时隙发送的概率 τ,然后推导出成功传输概率和冲突概率。第 14 章用仿真验证了理论结果,FSM 思路的 DCF 仿真代码框架也给了。这部分适合做 WLAN 性能研究的人参考。

链路模型和信道模型是物理层性能分析的基础。文档从 Free-Space Path Loss 讲到 SISO 信道模型和 Break Point 距离,再到菲涅尔区域。传输范围的理论计算也给了公式和示例。这些内容在做无线覆盖规划时会用到。

3. 把文档里的机制落到实际调试:抓包、参数与验证

3.1 用 Wireshark 验证 CSMA/CA 和 BEB 行为

文档里的时序图看懂了是一回事,实际抓包能不能对上又是另一回事。我一般会搭一个最小的测试环境:一台 AP,两台 station,其中一台用 iperf3 打流,另一台在 monitor 模式下抓包。

抓包时重点看这几个字段:

  • Duration 字段:RTS/CTS 帧里的 Duration 值就是 NAV 的设置依据。如果看到 Duration 明显偏大,说明有站占着信道不放。
  • Retry 标志位:数据帧的 Retry 位置 1 表示这是重传帧。连续多个 Retry 帧说明碰撞频繁。
  • More Fragments 位:分片传输时用,跟 RTS/CTS 阈值配合。
  • Sequence Number:同一个 MSDU 的分片共享序列号,重传时序列号不变。

下面这段是 tshark 过滤重传帧的命令:

# 过滤所有重传的数据帧,输出帧号、源地址、序列号和重试标志 tshark -r capture.pcap -Y "wlan.fc.retry == 1 && wlan.fc.type == 2" \ -T fields -e frame.number -e wlan.sa -e wlan.seq -e wlan.fc.retry

逻辑说明:wlan.fc.retry == 1筛出重传帧,wlan.fc.type == 2限定数据帧类型。输出里如果看到同一个源地址的序列号反复出现且 Retry 位都是 1,基本可以判断这个站处于持续碰撞状态。这时候可以去看它的 CW 值是不是已经翻到 CW_max 了。

参数说明:-Y是显示过滤器,跟 Wireshark 界面里的过滤语法一致。-T fields指定输出字段,-e后面跟字段名。如果抓包文件里包含 radiotap 头部,还可以加-e radiotap.dbm_antsignal看 RSSI。

3.2 调整 RTS/CTS 阈值和 CW 参数

Linux 下用iw命令可以查和改无线接口的参数。先看当前配置:

# 查看无线接口的详细参数,包括 RTS 阈值、分片阈值、发射功率 iw dev wlan0 info iw phy phy0 info | grep -A 5 "Fragmentation threshold"

改 RTS 阈值:

# 设置 RTS 阈值为 512 字节,超过这个长度的帧会先发 RTS sudo iw phy phy0 set rts 512

逻辑说明:RTS 阈值设小一点,更多帧会走 RTS/CTS 流程,能减少大帧碰撞的概率,但会增加开销。设大一点则相反。文档里提到 RTS/CTS 适合隐藏终端场景,如果抓包发现碰撞主要来自隐藏终端,可以把阈值调低到 256 或 512 试试。

参数说明:phy0是物理层设备名,用iw phy可以列出。set rts后面跟字节数,设成off可以关闭 RTS/CTS。

CW 参数一般驱动层不直接暴露给用户调,但可以通过iw的set bitrates间接影响。更直接的方式是改驱动模块参数,比如ath9k的cwmin和cwmax:

# 查看 ath9k 驱动的当前参数 systool -v -m ath9k | grep -E "cwmin|cwmax" # 临时修改 CW 最小值(需要重新加载驱动生效) sudo modprobe -r ath9k sudo modprobe ath9k cwmin=7 cwmax=15

逻辑说明:CW_min 设小会让站更快进入发送状态,适合低密度场景。CW_max 设小会让退避窗口上限降低,碰撞后恢复更快,但高密度场景下反而容易加剧碰撞。文档里 Bianchi 模型的分析可以用来预估不同 CW 值下的吞吐量变化。

参数说明:cwmin和cwmax是 2 的幂次减一的形式,比如 7 对应 CW=8,15 对应 CW=16。不同驱动的参数名可能不一样,iwlwifi用的是11n_disable之类的参数,具体要看驱动文档。

3.3 用 RSSI 和 CCA 阈值判断信道质量

文档里讲了能量检测和载波侦听两种 CCA 方式。实际调试时,RSSI 是最直观的指标。Linux 下可以用iw定期采样:

# 每秒采样一次 RSSI,输出时间戳和信号强度 while true; do echo "$(date +%H:%M:%S) $(iw dev wlan0 link | grep signal)" sleep 1 done

逻辑说明:这个脚本用来观察 RSSI 的波动情况。如果 RSSI 在 -70dBm 附近频繁跳动,说明信道上有其他设备在活动,CCA 会频繁置忙。文档里提到能量检测阈值通常在 -62dBm 到 -82dBm 之间,具体值取决于芯片实现。如果 RSSI 长期低于 -80dBm,站可能会因为 CCA 一直检测不到信号而贸然发送,导致碰撞。

参数说明:iw dev wlan0 link输出的 signal 字段就是当前关联 AP 的 RSSI。如果要看周围所有 AP 的 RSSI,用iw dev wlan0 scan | grep -E "SSID|signal"。

CCA 阈值一般不能直接改,但可以通过调整发射功率来间接影响。发射功率降低,覆盖范围缩小,同频干扰也会减少:

# 设置发射功率为 15dBm sudo iw phy phy0 set txpower fixed 1500

逻辑说明:1500的单位是 mBm(毫贝毫瓦),1500mBm = 15dBm。文档里链路模型那章讲了发射功率和传输范围的关系,Free-Space Path Loss 模型下,功率每降低 6dB,传输距离减半。实际调的时候要结合覆盖需求来定。

4. 避坑与排查:文档里没写但实际会遇到的五个问题

4.1 抓包看不到管理帧,只有数据帧

现象:Wireshark 里只能看到 Data 帧,Beacon、Probe Request/Response、Association 这些管理帧一个都没有。

原因:网卡没有进入 monitor 模式,或者 monitor 模式配置不正确。有些网卡在 monitor 模式下会过滤掉管理帧,只上报数据帧。

解决:先确认网卡支持 monitor 模式,用iw list看Supported interface modes里有没有monitor。然后手动创建 monitor 接口:

# 创建 monitor 接口 sudo iw dev wlan0 interface add mon0 type monitor sudo ip link set mon0 up # 用 tcpdump 验证是否能抓到 Beacon 帧 sudo tcpdump -i mon0 -c 10 -e -s 256 type mgt subtype beacon

如果还是抓不到,检查信道是否锁定。monitor 接口默认跟随主接口的信道,如果主接口没连 AP,信道可能是随机的。用iw dev mon0 set channel 6锁定到目标信道。

4.2 BEB 退避导致延迟抖动,VoIP 通话断续

现象:Wi-Fi 上跑 VoIP 时通话断续,抓包看到语音包的间隔忽大忽小,Retry 帧比例不高但延迟抖动明显。

原因:BEB 退避本身就会引入随机延迟。每次信道从忙变闲,站都要等 DIFS 加随机退避。如果 CW 值较大,退避时间可能超过语音包的容忍延迟。

解决:文档里 PCF 那章提到了轮询机制,但实际部署中 PCF 很少用。更常见的做法是用 WMM(Wi-Fi Multimedia)给语音包更高的优先级。WMM 把流量分成四个 AC(接入类别),语音是最高优先级,CW_min 和 AIFS 都比普通数据小。检查 AP 和 station 是否都开启了 WMM:

# 查看 station 的 WMM 状态 iw dev wlan0 link | grep -i wmm

如果 AP 不支持 WMM,考虑换 AP 或者用有线回程。另外,语音包的打包间隔建议设成 20ms,不要用 10ms,给退避留更多余量。

4.3 节能模式下站收不到下行数据

现象:手机连上 Wi-Fi 后锁屏一段时间,再解锁时微信消息延迟很久才收到,甚至要手动开关 Wi-Fi 才能恢复。

原因:站进入 PSM 深度睡眠后,AP 缓存的帧超过了 Listen Interval 能覆盖的范围,或者 TIM 帧里的 Bitmap 没有正确置位。文档里 PSM 那章讲了 AID 和 TIM 的对应关系,如果 AP 的缓存管理有问题,站醒来后看不到自己的 bit,就不会发 PS-Poll。

解决:先确认 AP 的 DTIM 周期设置。DTIM 是 TIM 的一种特殊形式,每隔几个 Beacon 发一次,站必须在 DTIM Beacon 时醒来检查是否有广播/组播数据。DTIM 周期设太大(比如 5 以上)会导致延迟增加。一般建议 DTIM 周期设 1 到 3。

# 查看 AP 的 DTIM 周期(需要 AP 支持) iw dev wlan0 scan | grep -i dtim

如果 AP 侧改不了,可以在 station 侧调整 Listen Interval。Linux 下用iw连接时指定:

# 连接 AP 时指定 Listen Interval 为 3 个 Beacon 间隔 sudo iw dev wlan0 connect MyAP freq 2437 listen 3

4.4 隐藏终端导致吞吐量骤降

现象:两个 station 离 AP 距离差不多,单独测都能跑满,同时打流吞吐量直接掉到三分之一以下。

原因:典型的隐藏终端问题。两个 station 互相听不到对方的信号,但都能听到 AP。站 A 在发送时,站 B 的 CCA 检测不到,以为信道空闲就发了,结果在 AP 处碰撞。文档第 5 章专门讲了这个问题。

解决:开 RTS/CTS。把 RTS 阈值调到比平均帧长小一点,让数据帧先发 RTS 预约信道。AP 回 CTS 后,所有能听到 AP 的站都会更新 NAV,包括隐藏站。代价是 RTS/CTS 本身的开销,小包场景下吞吐量可能反而降。

# 把 RTS 阈值调到 256 字节 sudo iw phy phy0 set rts 256

如果 RTS/CTS 效果不好,考虑降低发射功率或者调整 AP 位置,让两个 station 能互相听到。再不行就换信道,避开干扰。

4.5 Bianchi 模型算出来的吞吐量和实测对不上

现象:用文档里的 Bianchi 模型公式算出来的归一化吞吐量是 0.85,实际 iperf3 测出来只有 0.45。

原因:Bianchi 模型有几个强假设:理想信道无误码、所有站饱和发送、帧长固定、无捕获效应。实际环境里误码率、非饱和流量、变长帧都会拉低吞吐量。文档第 13 章列了模型的假设条件,第 14 章的仿真验证也是在理想条件下做的。

解决:把 Bianchi 模型当上限参考,不要当预测值。实际分析时,先确认测试条件是否接近模型假设:用 UDP 打流而不是 TCP(TCP 有拥塞控制),帧长固定(用iperf3 -l指定长度),关闭其他干扰源。如果实测和理论差距在 30% 以内,基本可以接受。差距太大就检查是否有隐藏终端、信道干扰、或者驱动 bug。

# 用 iperf3 打 UDP 流,固定帧长 1470 字节,测试 60 秒 iperf3 -c 192.168.1.100 -u -l 1470 -t 60 -b 100M

逻辑说明:-u指定 UDP,-l 1470指定 payload 长度,-b 100M限制带宽避免过载。UDP 没有重传和拥塞控制,更接近 Bianchi 模型的饱和发送假设。测出来的吞吐量除以理论物理层速率,就是归一化吞吐量。

5. 用 Python 复现 Bianchi 模型:从公式到数值求解

文档第 13 章给了 Bianchi 模型的公式,但没给完整的数值求解代码。我一般会自己写一个脚本,把理论曲线画出来,跟仿真结果对比。这样调参数的时候心里有数。

Bianchi 模型的核心是求解传输概率 τ。在稳态下,站在一个随机时隙发送的概率 τ 满足:

τ = 2 / (1 + W + p * W * Σ(2p)^i)

其中 W = CW_min,p 是冲突概率,i 从 0 到 m(最大退避阶数)。p 又跟 τ 相关:p = 1 - (1 - τ)^(n-1),n 是站的数量。这是一个不动点方程,需要用迭代法求解。

下面是用 Python 实现的求解代码:

import numpy as np import matplotlib.pyplot as plt def bianchi_tau(n, W=16, m=5, tol=1e-10, max_iter=1000): """ 求解 Bianchi 模型中的传输概率 tau n: 站的数量 W: CW_min + 1,即最小竞争窗口大小 m: 最大退避阶数 """ tau = 1.0 / W # 初始猜测 for _ in range(max_iter): # 冲突概率 p p = 1 - (1 - tau) ** (n - 1) # 根据 p 计算新的 tau # 求和部分:sum_{i=0}^{m} (2p)^i if p == 0: s = m + 1 else: s = (1 - (2 * p) ** (m + 1)) / (1 - 2 * p) if abs(1 - 2 * p) > 1e-12 else m + 1 tau_new = 2.0 / (1 + W + p * W * s) if abs(tau_new - tau) < tol: return tau_new, p tau = tau_new return tau, p def bianchi_throughput(n, W=16, m=5, L=8184, R=54e6, sigma=9e-6, Ts=None, Tc=None): """ 计算归一化吞吐量 n: 站的数量 W: CW_min + 1 m: 最大退避阶数 L: 平均帧长(bit),默认 8184 bit = 1023 字节 R: 物理层速率(bps),默认 54Mbps sigma: 空时隙长度(秒),默认 9us Ts: 成功传输的平均时间(秒) Tc: 冲突传输的平均时间(秒) """ tau, p = bianchi_tau(n, W, m) Ptr = 1 - (1 - tau) ** n # 至少有一个站发送的概率 Ps = n * tau * (1 - tau) ** (n - 1) / Ptr if Ptr > 0 else 0 # 发送成功的概率 # 默认时间参数(802.11a/g,长帧) if Ts is None: # Ts = DIFS + RTS + SIFS + CTS + SIFS + DATA + SIFS + ACK # 简化计算:DIFS=34us, RTS=20us, CTS=20us, ACK=20us, SIFS=16us Ts = 34e-6 + 20e-6 + 16e-6 + 20e-6 + 16e-6 + L / R + 16e-6 + 20e-6 if Tc is None: # Tc = DIFS + RTS + SIFS + CTS(冲突时没有 DATA 和 ACK) Tc = 34e-6 + 20e-6 + 16e-6 + 20e-6 # 归一化吞吐量 S = Ps * Ptr * L / ( (1-Ptr)*sigma + Ptr*Ps*Ts + Ptr*(1-Ps)*Tc ) numerator = Ps * Ptr * L denominator = (1 - Ptr) * sigma + Ptr * Ps * Ts + Ptr * (1 - Ps) * Tc S = numerator / denominator return S, tau, p # 画图:不同站数下的归一化吞吐量 n_values = range(1, 51) S_values = [] for n in n_values: S, _, _ = bianchi_throughput(n) S_values.append(S) plt.figure(figsize=(10, 6)) plt.plot(n_values, S_values, 'b-', linewidth=2) plt.xlabel('Number of Stations (n)') plt.ylabel('Normalized Throughput (S)') plt.title('Bianchi Model: Throughput vs Number of Stations') plt.grid(True, alpha=0.3) plt.axhline(y=0.9, color='r', linestyle='--', label='Ideal max') plt.legend() plt.tight_layout() plt.savefig('bianchi_throughput.png', dpi=150) plt.show() # 输出几个关键点的数值 for n in [1, 5, 10, 20, 50]: S, tau, p = bianchi_throughput(n) print(f"n={n:3d} S={S:.4f} tau={tau:.6f} p={p:.4f}")

逻辑说明:bianchi_tau函数用不动点迭代求解 τ 和 p。初始猜测 τ = 1/W,然后反复计算 p 和新的 τ,直到收敛。bianchi_throughput函数在 τ 和 p 的基础上计算归一化吞吐量。公式里的 Ts 和 Tc 分别是成功传输和冲突传输的平均时间,代码里用了 802.11a/g 的典型值。

参数说明:W是 CW_min + 1,默认 16 对应 CW_min=15。m是最大退避阶数,默认 5 对应 CW_max=1023。L是平均帧长,默认 8184bit 约 1023 字节。R是物理层速率,默认 54Mbps。sigma是空时隙长度,802.11a/g 是 9μs,802.11b 是 20μs。

跑出来的曲线会显示:站数从 1 增加到 5 时吞吐量快速下降,10 个站以后趋于平缓,50 个站时归一化吞吐量大概在 0.6 到 0.7 之间。这个趋势跟文档第 13 章的结果分析是一致的。

实际验证时,把 iperf3 测出来的吞吐量除以物理层速率,跟曲线上的点对比。如果实测值明显低于理论值,先检查是否有隐藏终端或者信道干扰。如果实测值高于理论值,可能是模型参数设错了,比如 CW_min 实际值比默认值小。

从那以后我每次调 Wi-Fi 性能参数,都会先跑一遍这个脚本,把理论曲线画出来,再跟实测数据叠在一起看。偏差超过 20% 就说明环境里有模型没覆盖的因素,得回去查抓包。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询