资讯动态

用Wireshark嗅探ESP32的Wi-Fi通信:读懂802.11帧实战解析

发布时间:2026/10/20 15:33:22 来源:尧图企业网站定制
我一直觉得搞 Wi-Fi 通信的开发者手里不能只有串口日志和 AT 指令回显。很多时候设备报“连接失败”或者“数据发不出去”从日志里看一切正常但真正的问题出在空气里——电磁波上承载的那些 802.11 帧说了什么你根本不知道。这次这篇“WIFI通信协议全解析14”就用 Wireshark 把 ESP32 的通信数据原封不动嗅探出来带你看懂“WiFi 的语言”。这不是什么高端黑客技巧而是嵌入式开发和网络调试的基本功适合玩 ESP32、做 IoT 项目、或者单纯想搞懂 Wi-Fi 协议栈的开发者参考。1. 为什么说嗅探是读懂 WiFi 语言最直接的方式1.1 空口数据与传统抓包的本质区别很多人一开始会问我电脑上装个 Wireshark直接就能抓 Wi-Fi 包吗能抓但抓到的不是“WiFi 的语言”而是“网卡处理完之后吐给你的翻译稿”。常规模式下无线网卡驱动会先做一层筛选不是发给本机的帧直接丢掉是发给本机的帧才把 802.11 头部剥掉再把里面的 TCP/IP 数据包往系统协议栈里送。Wireshark 看到的已经是剥离了 WiFi 帧头的数据相当于你只看到了快递里的商品没看到快递单上写了什么。而空口嗅探完全不同。它把无线网卡切换到监听模式让网卡放弃一切筛选和地址过滤把物理层收到的每一个 802.11 帧都完整保存下来。这里面包括Beacon 帧——AP 每 100ms 左右广播一次“我是谁、我在哪个信道、支持什么速率”Probe Request / Response——设备主动扫描时喊一嗓子“这附近有网络吗”AP 回应“有你连我吧”Association Request / Response——设备决定加入某个 AP 时相互确认身份和参数的对话数据帧——真正的业务数据但注意在加密网络里载荷是看不见的能看的是头部信息。对于 ESP32 这类嵌入式设备串口日志只能告诉你“我要连 router_a”但空口抓包能告诉你它发出 Probe Request 时到底扫描了哪些信道、AP 回了什么能力集、关联时协商了哪些参数、后续每帧数据相隔多久。这些东西才是定位 Wi-Fi 通信问题的一手证据。1.2 Wireshark 为什么是首选工具同类工具不是没有比如 Omnipeek、tcpdump 配合 monitor 模式也能干但 Wireshark 在“看懂”这件事上做得最好具体有三点第一它对 802.11 协议族的解码非常完整管理帧里的每一个 TagSSID、Supported Rates、HT Capabilities、802.11ax 的 HE 字段等都能按字段拆开鼠标点一点就能看每个 bit 的含义。第二它有一套强大的过滤语言可以快速从一整包文件里筛出你要的那台 ESP32 的帧。第三它是纯图形界面交互式展开、时间序列分析、IO 图表这些功能对新手非常友好。不过我要说句公道话Wireshark 的解码能力强不代表它是万能的。它只是个解剖台把帧拆开给你看但“为什么会出现这个帧”“这个帧说明什么问题”依然需要你对 802.11 协议本身有基本了解。也就是说Wireshark 帮你“看见”但“看懂”还得靠你自己。1.3 抓包方案的总体设计思路针对 ESP32 这个对象我的抓包方案一般分三种场景清晰区分能达到的目的场景 AESP32 作为 Station 连接附近的路由器。这时抓包能看到完整的扫描、关联、加密握手、正常通信流程。适合排查“连不上 Wi-Fi”“频繁掉线”“数据发送延迟大”这类问题。场景 BESP32 作为 SoftAP自己发射热点。这时抓包能看到 ESP32 自己发出去的 Beacon 帧和管理帧非常直观适合做协议教学和参数验证。场景 C两台 ESP32 之间做 Wi-Fi 直连或组网配合抓包分析它们之间的管理帧交互。这篇文章里的实操部分我会同时覆盖场景 A 和场景 B因为这两个场景最容易上手也最能帮你建立对“WiFi 语言”的直观认知。2. 抓包前的环境准备网卡、驱动与监听模式2.1 无线网卡选型与监听模式原理要监听空口数据第一道坎是网卡。普通笔记本内置网卡能不能开监听模式部分可以但多数 Windows 驱动不支持macOS 更是基本没戏。我的经验是亲手试过才最稳。我建议选用带 USB 接口的外置无线网卡方案。这类网卡驱动在 Linux 下相对容易切换监听模式对 802.11 帧的保留也比较完整包括前面我提到的管理帧、控制帧、数据帧都能收到。核心硬件选型思路是优先找那些在开源驱动列表里标注支持 monitor mode 的芯片方案获取方式不做具体推荐但市面上常见 USB 无线网卡大多都有对应方案。我平时备两片网卡一片是自用的普通连接网卡一片专门拿来监听。原因很简单——监听时网卡不能同时正常上网专门备一块不影响日常开发。提示监听模式和普通模式的区别最核心的就是网卡驱动是否执行地址过滤。普通模式下驱动只把目的地址匹配本机或组播/广播的帧上报监听模式下网卡把射频前端收到的所有帧全部上报。所以监听模式也叫 RFMONRadio Frequency Monitor它更像是“无线电收音机”不是“对讲机”。2.2 三步开启监听模式以 Linux 环境为例相对省心的环境是 Linux多数发行版对无线网卡的监听模式支持比较完善。以下命令需要 root 权限操作前确保网卡没有被系统网络管理服务占用。第一步确认接口名。插上网卡后运行iw dev输出里能找到类似phy#0、Interface wlan0这样的信息记住接口名后面全用这个名字。第二步切换监听模式。执行sudo ip link set wlan0 down sudo iw dev wlan0 set monitor none sudo ip link set wlan0 up这里有一个细节iw dev wlan0 set monitor none后面的none表示不附加任何过滤参数。有些网卡驱动支持fcsfail、control等额外参数新手不建议加先保证能干净地收到帧再说。第三步固定信道。Wi-Fi 在 2.4GHz 频段有多个信道网卡在同一时刻只能监听一个信道。先知道 ESP32 连的路由器工作在哪个信道然后用sudo iw dev wlan0 set channel 6把监听信道固定住。信道不对的话你会惊讶地发现明明设备在拼命运数据Wireshark 里却安静得像个假抓包。如果你用的不是 LinuxWindows 下要额外安装对应网卡的抓包驱动macOS 则基本只能靠特殊方式处理不太适合入门。所以我的建议是新手做这个实验优先整个 Linux 环境最简单的方案是配一台小型 Linux 主机或虚拟机加 USB 网卡直通。2.3 Wireshark 关键显示设置启动 Wireshark在接口列表里选择刚才进入监听模式的网卡接口通常是 wlan0 或者以 mon 开头的虚拟接口双击开始抓包。看到满屏幕的 Beacon 帧就说明监听成功了——周围所有 AP 的广播都进了你的抓包文件这就是监听模式和普通模式一眼就能看出来的差异。不过这时候你看到的管理帧可能是乱糟糟的一堆因为 Wireshark 默认会用普通的以太网解析逻辑去解析 802.11 帧头偶尔会出现解析不对的情况。如果看到帧头字段明显异常可以右键那条记录选择“Decode As”把协议强制指定为 IEEE 802.11网络层还是保留原来的 IPv4 或 IPv6。接下来顺手做两个设置能让后面省很多事显示列调整右键任意列头添加Source和Destination列这样每条记录的源和目的 MAC 地址能直接显示出来。在空口抓包里这两个字段对定位设备非常关键。时间显示格式进入 View - Time Display Format改成Seconds Since Previous Captured Frame。后面分析设备是否规律发包时这个时间差列一眼就能看出节拍对不对。做完这些抓包环境就绪了。下面进入真正的实操环节。3. 完整实操用 Wireshark 抓取并看懂 ESP32 的通信全程3.1 最小实验场景搭建为了让抓包过程可控我搭了一个最小实验台一个 ESP32 开发板烧录一个最简单的 TCP Client Demo一台家用无线路由器关掉其它无关终端混入干扰以及监听用的 USB 网卡 Wireshark。烧录之前先在程序里把 ESP32 的工作模式配置清楚我这里给出一种常见的初始化结构#include string.h #include freertos/FreeRTOS.h #include freertos/task.h #include esp_wifi.h #include esp_event.h #include esp_log.h #include nvs_flash.h static const char *TAG wifi-sniffer-demo; static void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { if (event_base WIFI_EVENT event_id WIFI_EVENT_STA_START) { esp_wifi_connect(); } else if (event_base WIFI_EVENT event_id WIFI_EVENT_STA_CONNECTED) { ESP_LOGI(TAG, connected to AP); } else if (event_base WIFI_EVENT event_id WIFI_EVENT_STA_DISCONNECTED) { ESP_LOGI(TAG, disconnected, retrying...); esp_wifi_connect(); } } static void wifi_init_sta(void) { wifi_init_config_t cfg WIFI_INIT_CONFIG_DEFAULT(); esp_wifi_init(cfg); esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, wifi_event_handler, NULL, NULL); wifi_config_t wifi_config { .sta { .ssid DEMO_AP, .password demo_password, .threshold.authmode WIFI_AUTH_WPA2_PSK, }, }; esp_wifi_set_mode(WIFI_MODE_STA); esp_wifi_set_config(WIFI_IF_STA, wifi_config); esp_wifi_start(); } void app_main(void) { nvs_flash_init(); wifi_init_sta(); }这段代码的核心意图是让 ESP32 只做一件事上电后初始化 Wi-Fi 协议栈然后以 Station 模式扫描并连接指定的 SSID。为了观察效果我还建议在连接成功之后周期性地向局域网内某个固定 IP 发送 UDP 包数量不需要多一秒一个就够这样空口抓包里能看到明显的周期性数据帧。3.2 从复位到连接一次完整的抓包现场记录实验环境就绪之后我把 USB 网卡固定在 ESP32 开发板附近两米以内固定监听信道到路由器所在信道开始抓包。然后给 ESP32 上电复位。Wireshark 里的帧就开始噌噌往外冒种类和顺序是一个标准的 Wi-Fi 连接流程第一步是扫描阶段。ESP32 发出一串 Probe Request 帧目的地址是广播地址 FF:FF:FF:FF:FF:FFSSID 字段要么是空表示“扫描所有网络”要么直接写着目标 SSID 的名称表示“精准扫描某个网络”。我用的是“DEMO_AP”所以能看到带有指定 SSID 的 Probe Request。第二步是 AP 回应。路由器收到 Probe Request 后回一个 Probe Response。注意这个帧的目的地址变成了 ESP32 的 MAC 地址里面携带了该 AP 的能力集、支持的速率、加密方式等信息。第三步是认证和关联。ESP32 发起 Association Request表示“我确认要加入你”。AP 回应 Association Response里面带着协商结果和一个关联 IDAID。到这里管理层面的关系就建立好了。第四步是加密握手。如果网络是 WPA2-PSK接下来会有四次 EAPOL 握手帧抓包里过滤eapol就能看到。这个过程协商出真正的会话密钥之后的数据帧都使用这个密钥加密。第五步是正常通信。连接完成后ESP32 开始周期性发送 UDP 数据包。这些数据帧的特征是帧控制字段类型为 DataType2并且目的地址是路由器的 MAC 地址而不是广播地址。我在实际操作中经常用过滤表达式直接锁定 ESP32一条就够了wlan.addr 34:85:18:aa:bb:cc把aa:bb:cc替换成你手里开发板的实际 MAC 地址。Wireshark 里所有源地址或目的地址命中这个 MAC 的帧都会被选出来形成一条独立的连接时间线。注意MAC 地址在 ESP32 上可以用esp_read_mac()读取也可以用esptool读 efuse 内容或者直接在路由器后台“已连接设备列表”里找。如果你把过滤条件写错了最常见的表现是抓包文件里一直有流量但过滤窗口一个帧都没有。3.3 抓到的帧怎么看关键字段逐一拆解拿到帧之后重点看哪些字段我按“看帧先看头”的思路给你拆一遍。所有 802.11 帧都以一个固定头部开头其中最重要的两个部分是帧控制字段和地址序列。帧控制字段里Type 决定大类管理帧、控制帧、数据帧Subtype 决定具体用途。我给你一个最常见的速查表类型Subtype 值用什么过滤含义管理帧8wlan.fc.type_subtype 0x08BeaconAP 周期性广播管理帧4wlan.fc.type_subtype 0x04Probe Request设备主动扫描管理帧5wlan.fc.type_subtype 0x05Probe ResponseAP 响应扫描管理帧0wlan.fc.type_subtype 0x00Association Request关联请求管理帧1wlan.fc.type_subtype 0x01Association Response关联响应数据帧0wlan.fc.type 2普通数据帧载荷可能加密控制帧特定wlan.fc.type 1ACK、RTS、CTS 等地址序列里有三到四个 MAC 地址字段分别表示接收端、发送端、BSSID 和有些帧才有源/目的端。在数据帧里通常能看到接收端RA通常是路由器 MAC发送端TA通常是 ESP32 MACBSSID路由器 BSSID基本等于 AP 的 MAC。为什么普通网络抓包看不到这几个地址因为普通网卡驱动已经把它们剥掉只留 IP 层了。看空口抓包这几个地址就是判断“这个帧到底是谁发给谁的”最重要的依据。再说 Beacon 帧。Beacon 非常值得单独拆一次因为它是所有 Wi-Fi 网络“存在感”的来源。展开一个 Beacon 帧你会看到Beacon Interval通常为 100ms表示 AP 每隔这么长时间广播一次Capability Info包括 ESS、Privacy 等标志位Privacy 置 1 表示网络启用了加密Tagged Parameters这一部分藏着 SSID 名称、支持的速率列表、信道号、HT Capabilities、Vendor Specific 字段。我用一个生活化类比Beacon 帧相当于店铺门口循环播放的“营业中”广播。它每隔一段时间喊一次告诉大家“这家店在我用的是 WPA2 加密支持这些支付方式”。而 Probe Request 就是顾客走到门口问一句“你们这里卖什么”Probe Response 则是店员出来说“我们卖这些价格是这些”。对于 ESP32 的调试最实用的信息其实在“时间”维度上。展开数据帧列表看 Time 列的 delta 值如果 ESP32 设定一秒发一个 UDP 包那么相邻数据帧的间隔应该稳定在 1000ms 左右。如果出现大的抖动或者丢帧说明空中信道拥挤、AP 队列拥塞或者 ESP32 在重传这些都是性能排查的重要线索。我看到过不少朋友第一次抓到 ESP32 的数据帧时会犯一个“想当然”的错误以为数据帧载荷里能看到自己发的 UDP 报文内容。在开放网络无加密下确实可以但在 WPA/WPA2 加密网络下数据帧的载荷是一段密文Wireshark 只显示为Data字段里面是 EAPOL 协商出来的 PTK 加密后的结果。能看到的只有帧头、长度、时间戳、速率这些元数据。所以空口抓包的重点从来不是“看明文内容”而是“看通信过程和时间特征”。4. 常见问题与排查技巧实录4.1 抓不到包时的排查路径我把这几年实际踩过的坑整理成一份排查路径按出现频率排序逐条对号入座。现象可能原因解决办法接口列表没有监听接口网卡驱动不支持 monitor 模式换 USB 网卡方案确认芯片方案在开源驱动的支持列表里网卡切换到 monitor 模式后抓到的全是 Beacon监听信道不对先确认 ESP32 关联的路由器信道用 iw 固定信道抓包文件里确实有 ESP32 的帧但看不到过滤表达式 MAC 写错从路由器后台或者 ESP32 日志里抄准确的 MAC能看到管理帧但一直没有数据帧ESP32 还没连接成功或者连接后没有业务流量检查串口日志里 STA_CONNECTED 事件是否触发Beacon 帧 CRC/ FCS 错误很多环境干扰强、网卡离 AP 太远靠近设备采用高增益天线或者降低周边同频干扰Wireshark 显示帧头解析成乱码没有正确解码 802.11右键 Decode As选择 IEEE 802.11最坑的一次我印象很深ESP32 明明通过串口打印已经连上 AP 了但抓包里怎么都找不到数据帧。折腾半天发现是我把固定监听信道设成了路由器当前工作信道旁边的那个。Wi-Fi 信号不跨信道可见监听信道错了哪怕设备在离你 1 米的地方发数据你的网卡也听不到。另一个非常影响体验的坑是系统网络服务管理工具抢占网卡。在 Linux 下如果你开启了网络管理服务它可能会在你设完 monitor 模式后自动把网卡“拉回”普通模式。解决方法是先把接口从网络管理服务里排除或者直接用命令行禁用对该接口的管理再进入监听模式。4.2 过滤表达式速查表与使用技巧Wireshark 的过滤表达式是阅读空口抓包的核心技能。我的习惯是每次抓包只建立一个“目标设备视角”的窗口把与当前任务无关的帧全部过滤掉。下面是我常驻收藏的几个表达式需求过滤表达式只看某台设备的收发帧wlan.addr 34:85:18:aa:bb:cc只看 Beacon 帧wlan.fc.type_subtype 0x08只看 Probe Request / Responsewlan.fc.type_subtype 0x04 || wlan.fc.type_subtype 0x05只看数据帧wlan.fc.type 2只看加密握手帧eapol只看某个 BSSID 的帧wlan.bssid 34:85:18:00:11:22看某个信道上的所有帧wlan_radio.channel 6过滤表达式能组合使用比如“我要看 ESP32 发出的数据帧”可以用wlan.addr 34:85:18:aa:bb:cc wlan.fc.type 2这样过滤之后剩下的帧就全是你目标设备的数据通信记录了再配合时间列看通信间隔非常干净。组合过滤里需要注意的一点是wlan.addr会同时匹配 TA 和 RA所以“只看 ESP32 发给别人的帧”和“只看别人发给 ESP32 的帧”要分开看地址字段。前者用wlan.ta MAC后者用wlan.ra MAC。这个问题在分析 AP 和 STA 交互时特别值得区分。4.3 进阶方向结合 EAPOL 握手与离线分析如果你已经把前面的基础抓包玩得比较熟了可以往两个方向进阶。第一个方向是分析 EAPOL 握手也就是 WPA2/WPA3 的密钥协商过程。过滤eapol之后能看到四次握手的每一帧消息类型Message 1~4。如果你要排查“ESP32 连接稳定但网络层却不通”这种疑难杂症重点看 EAPOL 握手是否完整、PTK 是否成功生成。只要握手少了一轮后面的数据帧加密密钥就不一致表现就是能连上但数据完全不通。第二个方向是保存 pcapng 文件做离线分析。实时抓包时注意力容易分散把抓包文件存下来再回放分析能反复研究时间线。我经常做的一步是把 UDP 数据包间隔导出成 CSV 或者直接用 Wireshark 的 IO Graph 功能画时间分布图。如果图形上出现周期性的大缺口那基本可以断定空中信道存在被占用或者 AP 侧丢包。这个分析思路对于 ESP32 设备做低功耗间歇上报场景尤其有用。顺便补充一个实用技巧Wireshark 支持对加密网络做密钥导流。如果你知道 ESP32 和 AP 握手时的 PSK 以及通信双方的 MAC可以在 Wireshark 里配置解密密钥Edit - Preferences - Protocols - IEEE 802.11 - Decryption Keys。配好之后数据帧里的加密载荷会被实时解密你就能直接看到里面封装的 TCP/UDP 报文内容。这个功能在调试自有设备时非常有用但要注意密钥必须准确对应到当前会话否则解出来的全是乱码。5. 写在最后一点个人体会和一个可复用的技巧整个实操流程走下来我的感受是会用串口和 AT 指令只能算“会用 Wi-Fi 模块”能把 Wireshark 里的 802.11 帧讲清楚才算开始“读懂 Wi-Fi 的语言”。尤其是做 IoT、智能家居这类依赖无线连接的项目空口抓包应该作为调试标配手段而不是出了问题才想起来查。最后分享一个我每次都会用的小技巧抓包前在 ESP32 日志里打印自己的 MAC 地址然后在 Wireshark 里新建一个“目标设备”显示过滤器再开始抓包。这样整个调试过程非常清爽——所有无关的广播、Beacon、邻居终端的流量全部被过滤剩下的每一帧都跟你自己的设备直接相关定位问题至少要快一倍。希望这篇能帮你在 Wi-Fi 调试的路上少走几个弯路真去动手抓一次包你会发现原来那些藏在空气里的“语言”也没有那么神秘。

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

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

免费获取报价 →
↑