
1. 先说结论Wireshark 抓 MQTT 包到底在抓什么我最早接触 MQTT 和 Wireshark 组合是在调试一套设备上报链路的时候。当时设备端用的是 ESP32 走 MQTT 协议服务器端是自建的 EMQX中间还隔着一层 4G 路由器。设备上报数据时有时正常、有时丢失业务方一口咬定是“服务器吞了消息”服务器那边一口咬定“根本没收到”。两边都在甩锅唯一能一锤定音的就是抓包。用 Wireshark 抓 MQTT 报文本质上干的事情就三件确认报文到底有没有发出来、确认报文内容对不对、确认协议交互流程符不符合预期。它能直接回答“谁丢了消息”“谁改了数据”“谁没回 ACK”这类问题。这篇文章适合谁看适合正在调试 MQTT 设备接入、排查消息丢失、分析协议交互流程的人也适合刚接触 Wireshark、想找一个真实协议练手的入门者。我会从最基础的抓包姿势讲起一路走到过滤语法解析、报文结构拆解、重传与乱序分析最后附上我自己踩过的坑和排查经验。读完你就能拿着 Wireshark 自己上手抓一次 MQTT 包并且能看懂每一层在说什么。2. 环境准备把抓包工具链一次配齐2.1 Wireshark 安装与版本选择Wireshark 的安装没什么难度Windows、Linux、macOS 都有对应版本。Windows 下直接去官网下载安装包安装过程中会提示安装 Npcap这个一定要装它是 Windows 下抓包的核心驱动。版本选择上我的建议是别追新稳定版优先。Wireshark 对 MQTT 的解析支持已经很成熟了4.x 系列我用下来没有遇到过协议解析问题。如果你在公司内网环境可能还要注意安装权限的问题——Npcap 驱动需要管理员权限公司电脑锁了驱动安装的话抓包这步就做不了只能换台机器。Linux 下安装更简单sudo apt update sudo apt install wireshark -y安装过程中会询问是否允许非 root 用户抓包选择“是”。装完之后把当前用户加入 wireshark 组sudo usermod -aG wireshark $USER记得注销重新登录组权限才会生效。2.2 抓包前的系统配置别让本机防火墙和网卡捣乱很多人抓不到包不是因为工具不行而是系统或网卡在“捣乱”。Windows 上最容易踩的坑是防火墙拦截了 Wireshark 的抓包流量尤其是抓本机回环流量loopback的时候有些安全软件会静默拦截。建议抓包前临时关闭 Windows Defender 防火墙和第三方安全软件抓完再打开。macOS 和 Linux 下一般不用关防火墙但如果用的是公司统一部署的安全策略抓包可能直接失败报“No interface available”之类的错误这时候排查方向就是安全软件而不是 Wireshark 本身。网卡方面要注意的是混合模式Promiscuous Mode。默认情况下 Wireshark 抓的是发往本机的流量如果要抓经过本机网卡但目的地址不是本机的流量需要在捕获选项中勾选“Enable promiscuous mode on all interfaces”。调试 MQTT 设备时我经常把电脑和开发板接到同一个交换机上然后抓电脑网卡的流量来观察开发板与服务器之间的通信——这种情况下混合模式就是必需的。2.3 MQTT 测试环境搭建没有服务器也能动手抓包抓包这件事不能光看理论必须动手。为了演示方便我建议你本地搭一个极简的 MQTT 测试环境全程不需要公网服务器。第一步安装 Mosquitto这是一个轻量级的 MQTT Broker也是调试时最常用的工具。Windows 用户可以下载 Mosquitto 安装包装完后在命令行里启动mosquitto -v -p 1883-v参数让 Broker 在控制台输出详细日志-p 1883指定监听端口。默认端口就是 1883可以不加但显式写出来更清楚。Linux 下用 apt 安装后启动方式相同。启动成功后会看到类似Opening ipv4 listen socket on port 1883的日志。第二步准备一个 MQTT 客户端工具。我推荐 MQTTX它跨平台、图形化、操作直观能同时管理多个连接。你也可以用命令行工具mosquitto_pub和mosquitto_sub更轻量适合脚本化测试。第三步打开 Wireshark在捕获选项里选择本机网卡然后就可以开始抓包了。如果你只是想先感受一下 MQTT 报文长什么样可以只抓本地回环接口loopback然后在 MQTTX 里连接127.0.0.1:1883发布一条消息你就能在 Wireshark 里看到完整的 MQTT 交互。提示抓本机回环流量时Wireshark 显示的网络接口名一般是“Loopback: lo”或“Npcap Loopback Adapter”别选成物理网卡。3. MQTT 协议核心结构与 Wireshark 的解析对应关系3.1 四层结构从物理网卡到 MQTT 负载在 Wireshark 里展开一个 MQTT 报文你看到的是一个层级嵌套的树形结构。一个完整的 MQTT 报文在 Wireshark 里通常是这样的Frame物理层帧头Ethernet II数据链路层源 MAC、目的 MACInternet Protocol Version 4网络层源 IP、目的 IPTransmission Control Protocol传输层源端口、目的端口、序号、确认号MQ Telemetry Transport Protocol应用层MQTT 报文头、可变头、负载这个层级结构本身就是一次协议栈的“解剖演示”。MQTT 跑在 TCP 之上所以 TCP 的三次握手、四次挥手、重传、乱序全都会直接影响 MQTT 的传输效果。理解这一点特别重要——很多时候你看 MQTT 层是正常的但报文没到问题恰恰出在 TCP 层。举个我最常遇到的例子设备上报数据Broker 侧确实没收到消息Wireshark 抓包一看TCP 层出现了大量 DUP ACK 和 Retransmission。这说明数据包在链路上丢了TCP 在拼命重传但重传也超时了最终应用层根本拿不到完整数据。这种情况你要是只盯着 MQTT 层看永远找不到原因。3.2 MQTT 报文头固定头、可变头、负载的边界MQTT 报文分为三部分固定头Fixed Header、可变头Variable Header、负载Payload。其中只有固定头是每种报文都必须有的。固定头里的核心字段是“报文类型”和“剩余长度”。报文类型用 4 个 bit 表示取值从 1 到 14对应 CONNECT、CONNACK、PUBLISH、PUBACK、SUBSCRIBE、SUBACK、PINGREQ、PINGRESP、DISCONNECT 等。Wireshark 的 Info 列会直接把报文类型显示为Connect Command、Publish Message这类人类可读的名称。剩余长度字段表示“可变头 负载”的总字节数用的是变长编码最多 4 个字节表示 256 MB 以内的长度。数值小于 128 时占 1 个字节大于等于 128 时会把低 7 位先存下来最高位设为 1表示后面还有续字节剩下字节存进下一个字节去。第一次看 MQTT 报文时容易被剩余长度的编码绕晕但在 Wireshark 里你不需要手动算它会在解析树里直接给你展示“Remaining Length: 12”这样的十进制值。需要手动算的场景只有一个——你打算自己写一个 MQTT 客户端或者做二进制协议解析。这种情况下你就得搞懂“Modulo 128”这个循环逻辑否则编码容易出错。可变头部分按报文类型可选PUBLISH 报文的可变头里包含主题名和报文标识符。合法主题名的规则我建议你这样记必须至少 1 个字符不能包含通配符和#长度不能超过 65535 字节。当你看到 Wireshark 里 Topic 字段出现$share/...这种前缀说明抓到了共享订阅的报文——这是 MQTT 5.0 引入的组订阅机制。负载部分就一句话PUBLISH 报文里放着真正的业务数据。Wireshark 会根据 PUBLISH 报文的主题和内容自动做文本或 JSON 格式化显示方便你肉眼核对数据内容。3.3 三种 QoS 等级在报文交互中的差异MQTT 的 QoS 机制是协议最核心也最容易让人迷惑的模块Wireshark 里体现得淋漓尽致。QoS 0 是“尽力而为”发布端发出 PUBLISH 报文后不需要等待任何确认所以 Wireshark 里你只会看到一条 PUBLISH 报文后面没有 PUBACK、没有重传。这种模式下消息可能会丢但开销最小适合传感器高频上报的场景。QoS 1 是“至少一次”发布端发出 PUBLISH 报文后必须等待接收端回 PUBACK 报文。如果发布端在超时时间内没收到 PUBACK就会重新发送 PUBLISH 报文Wireshark 里会出现多条相同报文标识符的 PUBLISH。这个过程能保证消息到达但接收端可能收到重复消息所以接收端要做去重。QoS 2 是“恰好一次”它是最复杂的两轮握手发布端发 PUBLISH接收端回 PUBREC发布端收到 PUBREC 后发 PUBREL接收端收到 PUBREL 后回 PUBCOMP。四个报文一对齐消息才正式完成投递。Wireshark 里看到一个 PUBLISH、PUBREC、PUBREL、PUBCOMP 完整序列就能断定 QoS 2 交互正常。我强烈建议你用 Wireshark 分别抓一次三种 QoS 的发布流程亲眼看看报文序列的差异。这比盯着协议文档背十遍都管用。我自己当年就是靠这个办法彻底搞明白了“QoS 1 会重复、QoS 2 不会重复但慢”这个普遍共识背后到底是怎么运作的。4. 抓包实操从启动抓包到定位一条消息4.1 第一步选择正确的捕获接口打开 Wireshark 主界面你会看到一张网卡列表每个网卡后面有实时流量波形图。选错网卡是新手最容易犯的错。判断依据很简单看 IP 网段。如果你要抓的 MQTT 服务器 IP 是192.168.31.100你就要选 IP 为192.168.31.x网段的那个网卡。如果你连的是 Wi-Fi一般选名字里带 WLAN 或 Wireless 的那个如果是有线网选名字里带 Ethernet 的那个。不确定的话按流量的“波纹”来判断——正在收发数据的网卡波形会跳动。所有网卡波形都是平的说明当前没有网络流量或者你选的网卡不对。双击选中网卡后Wireshark 就进入捕获模式了。此时你会看到所有经过该网卡的数据包很多是无关的 ARP、DNS、TLS 流量先别管它们等抓到了 MQTT 包再过滤。4.2 第二步用显示过滤器把 MQTT 流量“拎”出来Wireshark 的过滤分为捕获过滤器抓之前过滤和显示过滤器抓之后过滤。调试 MQTT 时我一般先用显示过滤器因为抓的时候我并不知道 MQTT 会出现在哪条流里先全部抓下来只要流量不大抓完再用过滤器精确筛选。最简单的过滤语法就是直接写协议名mqtt这个过滤器会把所有 MQTT 报文列出来包括 CONNECT、SUBSCRIBE、PUBLISH、PINGREQ 等等。注意MQTT over WebSocket常见的浏览器端 MQTT 场景只写mqtt是过滤不出来的需要配合websocket协议一起过滤后面我单独讲。更精准的过滤方式是按报文类型过滤。Wireshark 的 MQTT 解析器会把报文类型映射成可过滤字段。例如mqtt.msgtype 33 代表 PUBLISH。如果你只关心设备发布的消息直接写这条过滤瞬间过滤掉握手和订阅报文。还有一种常见场景你只想看某个主题下的消息。主题名在mqtt.topic字段里过滤语法是mqtt.topic contains device/001contains做的是子串匹配做的是精确匹配。具体场景里按需选用。4.3 第三步追踪 TCP 流把上下文串起来MQTT 跑在 TCP 上你单独看一条 PUBLISH 报文可能看不出问题。真正有效的调试方式是右键点击任意一条 MQTT 报文选择“追踪流” - “TCP Stream”。Wireshark 会弹出一个窗口把这条 TCP 连接上的完整数据流按时间顺序展示出来。在这个窗口里你能看到完整的对话全貌客户端发 CONNECTBroker 回 CONNACK客户端发 SUBSCRIBEBroker 回 SUBACK之后就是 PUBLISH 和 PUBACK 的循环。整个交互是正常还是异常一眼就能判断。追踪 TCP 流还有一个高阶用法导出原始数据。Wireshark 的“追踪流”窗口右下角有一个“显示数据”按钮可以切换显示格式。默认是 ASCII 码MQTT 报文包含二进制数据时建议切换为 Hex Dump或者点“保存为文件”把负载部分导出再结合 Python 脚本做二次解析。这就是“Wireshark 可视化 脚本精确解析”组合拳的由来。4.4 第四步模拟一次完整的 MQTT 通信我建议你这样动手试一次步骤很短但能把 Wireshark 里 MQTT 的整个生命周期走一遍启动 Wireshark选中 Loopback 接口开始抓包。打开 MQTTX新建一个连接填入mqtt://127.0.0.1:1883。连接成功后订阅一个主题比如test/topic。再通过另一个会话或者mosquitto_pub发布一条 JSON 消息到同一个主题mosquitto_pub -h 127.0.0.1 -t test/topic -m {\id\:1,\value\:42}切回 Wireshark停止抓包过滤mqtt。此时你至少能看到这几类报文连接建立时的Connect Command和Connect Ack订阅时发送的Subscribe Request和服务器返回的Subscribe Ack发布时发送的Publish Message客户端收到的推送消息另一条成对出现的 Publish Message如果发布消息时使用了 QoS 1 或 2你还额外能看到 PUBACK 或 PUBREC/PUBREL/PUBCOMP 的完整流程。注意MQTTX 里默认 QoS 是 0所以不出意外的话你看到的发布过程只有一条 PUBLISH。别觉得这是“抓包失败”这是符合协议预期的正常表现。5. 进阶实战MQTT over TLS 和 WebSocket 的抓包姿势5.1 加密流量怎么抓配置 RSA Key 或者干脆看解密流MQTT 生产环境几乎都是 MQTT over TLS默认端口是 8883。TLS 加密之后的报文在 Wireshark 里只显示为Application Data你不会直接看到 MQTT 内容。这时候有两条路一是配置 TLS 解密二是干脆不关注 MQTT 内容、只分析 TLS 握手和 TCP 层。先说 TLS 解密。前提是你拿到 SSL Key Log File。在 MQTT 客户端比如 MQTTX里一般有导出 SSL Key 的选项或者在系统环境变量里设置export SSLKEYLOGFILE/tmp/mqtt_key.log然后重启客户端Wireshark 里选择“编辑” - “首选项” - “Protocols” - “TLS”在“(Pre)-Master-Secret log filename”里填入这个文件路径。设置完成后再抓包Wireshark 就会自动解密 TLS 流量MQTT 报文完整还原。这条路的限制是你必须能控制 MQTT 客户端并且在连接建立前就开启 Key 记录。如果是抓别人家设备的加密流量拿不到密钥就只能在 TCP 层分析。比如观察 TLS 握手是否完成ClientHello 到 ServerHello 再到 Finished以及是否有大量 TLS 重传这些信息已经能解决大部分“连接不稳定”的排查问题。5.2 WebSocket 封装下的 MQTT 解析设备端和网页端还有一个高频场景是 MQTT over WebSocket默认端口是 8083 或 8084TLS。这种连接里MQTT 报文被包装在 WebSocket 帧里Wireshark 的 MQTT 解析器虽会自动识别但如果你只过滤mqtt不一定能把所有消息筛出来因为协议栈里的 WebSocket 层有时会打断 MQTT 解析的连续性。我的经验是同时过滤两个协议mqtt || websocket另外WebSocket 连接在出现丢包时TCP 层表现会和普通 MQTT 稍有不同。WebSocket 有自己的帧掩码机制但掩码逻辑与应用层无关TCP 层面的重传和丢包排查方式仍然通用。我遇到过一次 WebSocket 连接不断断开重连的问题排查到最后Wireshark 里看到的 TCP 层有大量 Keep-Alive 超时和连接重置根本原因是客户端和服务器的 WebSocket Ping/Pong 间隔不一致。这种问题如果不抓 TCP 流只看应用层日志很难被发现。6. 高频场景实战给 485 设备发 MQTT 指令的问题排查6.1 网关链路里 Wireshark 抓包的位置选在哪485 设备走 MQTT 的场景在工业物联网里很常见Modbus RTU 设备通过串口接一个 MQTT 网关网关把 Modbus 数据转成 MQTT 报文发到 Broker业务平台再订阅消费。调试这种链路时最闹心的问题是“指令发出了但设备没动作”。Wireshark 在这条链路里能观测到的是 IP 层以上的部分也就是 MQTT 网关到 Broker 之间的通信。串口上的 Modbus 报文要用串口抓包工具或逻辑分析仪但 MQTT 指令是否正确到达、格式是否完整Wireshark 完全可以判断。抓包时位置选择的原则是越靠近“疑似故障点”越好。如果你怀疑网关没收到平台下发的指令就在网关所在局域网里的电脑上抓包网关和电脑接同一交换机过滤 MQTT 报文。如果你怀疑 Broker 没把指令转发出去就抓 Broker 服务器的网卡。6.2 用 Wireshark 判断“指令是否下发成功”的实操方法假设平台要向某个 485 设备通过网关接入下发写寄存器指令。MQTT 发送的报文主题一般是类似device/001/write的形式负载是一串十六进制数据比如010600010000Modbus 功能码 地址 寄存器值。在 Wireshark 里操作流程如下抓包后过滤mqtt.topic contains device/001/write找到对应的 Publish Message 报文展开 MQTT 层检查 Topic 字段是否完全匹配再看 Payload 数据对比你下发的十六进制原文如果 Topic 和 Payload 都对那问题就不在网络链路而在网关的串口侧——你需要转用串口工具看网关是否把 Modbus 数据真正发到了 485 总线上。如果 Topic 正确但 Payload 乱码检查客户端编码方式是否设置了 UTF-8。如果网关根本没有收到这条 MQTT 消息Wireshark 里连 PUBLISH 报文都找不到那就需要往上层排查——是 Broker 没投递还是订阅关系不匹配还是 QoS 和权限设置挡住了。6.3 一个真实排查案例的完整拆解我调试过一批温湿度传感器设备上报正常但平台下发控制指令偶尔失效。现场环境是传感器通过 RS485 到网关网关走 4G 网络连 MQTT Broker 服务器。平台反应“指令已经显示发送成功了”。我开始抓包把笔记本电脑接到网关的 LAN 口上此时网关工作在路由器模式下Wireshark 过滤mqtt.topic contains control很快看到了平台下发的 Publish Message。展开后发现负载是十六进制01 05 00 00 FF 00对应的 Modbus 命令是正确的“控制继电器闭合”。但继续往下一看Broker 回复的 PUBACK 报文迟迟没有出现。Wireshark 里 TCP 层几个疑似重传的包引起我注意点开后发现发布端发送的 PUBLISH 报文 TCP Seq 是正常的但 Broker 侧一直没有返回 ACK。这导致发布端一直处于等待状态指令实际并未到达 Broker。搞清真相后问题就好办了4G 网络的 UDP 通道虽然打通了但 TCP 层的丢包严重导致 MQTT QoS 1 的确认机制无法完成。最终的解决方案是调整网关的 TCP KeepAlive 参数和 Qos 等级——控制类指令从 QoS 1 降到 QoS 0 反而更可靠原因是 QoS 0 不依赖 PUBACK 确认单次发出后网关直接转发 Modbus 指令重试逻辑由平台业务层控制规避了 4G 网络下 TCP 传输不稳造成的二次故障。这类问题的核心教训是看 Wireshark 不能只看有没有 PUBLISH一定要看 TCP 层有没有完成确认循环。协议栈是分层的一层出问题上层再正常也不可靠。7. 常见问题排查速查表我踩过、你可能会遇到的坑我把这几年用 Wireshark 抓 MQTT 包遇到的典型问题整理成一张速查表排查时直接对照使用。现象可能原因排查方法解决方案抓不到任何 mqtt 报文过滤器写错、用的端口非 1883、流量走了别的网卡检查过滤器语法去掉过滤器看原始流量正确选择网卡和过滤条件改用 mqtt只有 ClientHello 没有 MQTT 内容MQTT over TLS 加密检查 TLS 首选项是否配置了 Key 文件配置 SSLKEYLOGFILE 或放弃解密查看 TCP 层MQTT 报文乱序、有大量 Retransmission网络丢包严重、4G 链路不稳定查看 TCP 层统计Statistics - TCP Stream Graph调整 TCP 超时参数或改用 QoS 0 应用层重试能看到 PUBLISH 但看不到 PUBACKQoS 0 发布或 QoS 1 确认丢失查 PUBLISH 报文头部 QoS 等级若 QoS 为 0则无 PUBACK 是正常的消息到达但顺序错乱设备并发发布、TCP 乱序检查 TCP 层是否乱序看 Seq 号加应用层消息序号Broker 端排序抓包文件巨大、卡顿抓包时间太长无关流量太多抓包前设置捕获过滤器只抓 1883 端口用tcp port 1883做捕获过滤掉帧问题也能缓解中文负载显示为乱码Wireshark 默认按 UTF-8 解码若字节流是 GBK 编码会显示异常展开 Payload 的“Raw Data”查看十六进制设备端改用 UTF-8 编码或解析时自行转码WebSocket 场景 MQTT 解析断断续续MQTT 被分片封装在多个 WebSocket 帧中过滤器同时加上websocket跟踪 TCP 流查看完整上下文7.1 关于“抓包文件巨大”的最优解法抓包文件太大的问题我吃过亏。有一次我在现场为了捕捉一条偶发的异常消息直接开着 Wireshark 抓了半小时最终文件达到了 2.3 GBWireshark 卡到无法正常操作过滤一下要等半分钟。事后我意识到问题出在抓包姿势上我应该用捕获过滤器只抓 1883 端口而不是抓完整网卡流量。捕获过滤器在驱动层面就过滤掉了无关流量。比如只抓 MQTT 流量tcp port 1883如果是 MQTT over TLS同时抓 8883tcp port 1883 or tcp port 8883这样抓到的文件大小能缩小几个数量级。另外抓包时还可以开启 Wireshark 的“多个文件”模式按文件大小自动切割避免单个文件过大。切出来的文件分析时可独立打开不影响上下文连贯性。7.2 中文负载显示乱码的解决思路MQTT 负载是二进制数据Wireshark 默认按 UTF-8 解码显示。如果你抓到的设备是国产单片机编码方式大多是 GBK/GB2312此时 Wireshark 的显示会变成一堆乱码比如“设备”变成“设澶”这种。这个时候别慌展开报文里的 MQTT 层找到 Payload 字段右键 - “作为二进制显示”或直接看底部的十六进制原始数据。用十六进制比对很快就能判断问题是否出在编码层。如果确认是 GBK 编码那这个设备端的数据传输规范就有隐患——建议设备端统一改成 UTF-8否则平台服务端去解析时同样会遇到编码问题。8. Wireshark 图形化分析技巧看得见才查得快8.1 TCP Stream Graph 怎么看链路质量Wireshark 不只是看单条报文它还能画出整个 TCP 连接的时序图。菜单栏“统计” - “TCP Stream Graph” - “Time-Sequence GraphStevens”选中后会弹出一个二维坐标图横轴是时间纵轴是 TCP 报文序号。通过这张图能看到连接里是否存在重传、乱序、窗口满等情况。正常平滑的图是一条稳定上升的斜线。如果你看到图中出现向下回跳的“锯齿”说明有乱序或重传。如果有一段区间是“水平直线”没有任何上升说明这段时间没有数据流动——可能是应用层在等待响应。如果出现大量锯齿和平台期基本可以确定链路质量有问题。我通常这样判断连接是否“健康”打开 Time-Sequence Graph如果斜率平滑、无大回跳链路基本没问题问题大概率在应用层如果锯齿密集、序号回退明显先去查网络丢包和延迟不要浪费时间在 MQTT 层找原因。8.2 I/O Graph 统计报文速率另一个常用工具是“统计” - “I/O Graph”它按时间统计每秒钟通过的报文数。调试高频 MQTT 上报场景时I/O Graph 能直接反映设备是否存在突发上报、是否符合预期周期。比如设备配置的是每 10 秒上报一次但你看到 I/O Graph 里每隔几秒就出现一个脉冲尖峰说明实际的上报频率和配置不一致可能是设备端定时器出了问题。如果曲线长时间处于低平状态说明设备断连了或者无数据上报。8.3 过滤器表达式进阶语法同时筛主题和 QoS看到这里你应该已经掌握了最基础的mqtt过滤。我再给你加几个每天都能用得上的进阶写法只显示 QoS 大于 0 的消息mqtt.qos 0只显示某个客户端 ID 的报文mqtt.clientid contains esp32-dev只显示订阅请求里的主题mqtt.topic contains device/#注意#在 MQTT 主题里是通配符但在 Wireshark 过滤器里如果你写mqtt.topic device/#它会被当作精确匹配的普通文本处理不会做通配扩展。Wireshark 过滤器遵循的是显示过滤器自身的语法contains、matches、和 MQTT 订阅语义无关这一点不要混淆。如果你要过滤“所有动作包含订阅成功”的报文可以这样组合mqtt.msgtype 9 || mqtt.msgtype 119 是 SUBSCRIBE11 是 SUBACK。需要的时候把数字换成对应的含义就行。9. 一个从 0 到 1 的排查实战完整拆解一次“消息丢失”案件给你还原一个我遇到过的真实场景一台环境监测设备每隔 5 秒上报一次 JSON 数据主题是env/sensor/01。某天业务方反馈“数据有周期性缺失有时候连续几分钟没数据”。很多人第一步会看 Broker 日志、看客户端日志但日志只能告诉你“服务端没收到”却无法告诉你“丢在哪个环节”。Wireshark 才是定位关键。我直接抓取局域网的流量设备通过 Wi-Fi 接入我电脑和它连同一 AP过滤mqtt.topic contains env/sensor/01观察了大约 3 分钟发现了三处异常。第一处异常PUBLISH 报文确实在设备端发出但 Broker 回复的 PUBACK 在部分周期里迟迟未到。这说明消息在“设备到 Broker”的链路上存在严重丢包。第二处异常部分 PUBLISH 报文在 TCP 层出现了重传重传间隔超过 1 秒。这种延迟换来的结果是 Broker 端收到了重复的 QoS 1 消息因为 PUBACK 丢失发布端重发了。第三处异常有些 PUBLISH 报文根本没有重传直接就空了——也就是说设备端的 TCP 发送队列可能已满新的数据被丢弃了。顺着这三个异常我把注意力转向 Wi-Fi 链路。在 I/O Graph 里观察发现周期性上报的脉冲和 Wi-Fi 的 Beacon 帧间隔有规律冲突进一步用 Wireshark 的“无线网卡监控模式”查看周边 Wi-Fi 干扰后确认是 Zigbee 设备和 Wi-Fi 抢占了 2.4G 频段数据碰撞严重。最终的核心解决手段是调整设备的 Wi-Fi 信道和上报频率把数据发送避开干扰高峰期。这个案例的核心价值在于用 Wireshark 把“消息丢失”这个模糊的问题拆解成了“PUBLISH 发出去了”“PUBACK 没回来”“TCP 重传产生了”“重传还是丢了”这四个精确的环节。一旦拆解到这个颗粒度解决方案就变得明朗起来。10. 扩展思路Wireshark 之外的 MQTT 抓包分析工具Wireshark 是主力但不是唯一。集成调试环境里我通常还会配合另外几种工具完成不同阶段的排查。第一类是 Broker 自带的诊断接口。EMQX 提供了 Dashboard能看到在线客户端数、订阅关系、消息速率。配合 Wireshark 的抓包数据可以交叉验证“Broker 到底收到了多少条消息”。如果 Wireshark 显示设备发出的消息数量远大于 Broker Dashboard 显示的数量那问题一定在 Broker 内部或网络链路上如果两边数量一致那消息丢失就大概率发生在业务消费端。第二类是命令行抓包工具 tcpdump。当你要长时间抓包、在 Linux 服务器上抓包或者抓包环境没有图形界面时tcpdump 是 Wireshark 的完美替代。抓完转成 pcap 文件再用 Wireshark 打开分析sudo tcpdump -i eth0 -w /tmp/mqtt.pcap tcp port 1883第三类是 MQTT 协议分析脚本。我常用 Python 写一个简单的 MQTT 解析脚本处理 Wireshark 导出的 JSON/CSV 数据大幅提升分析效率。Wireshark 自带“文件” - “导出分组解析结果” - “As JSON”导出的数据每个报文都带完整字段名和值用脚本做统计非常方便。比如统计每个主题的 Publish 数量、计算每个 PUBACK 的延迟、找出超时的报文这些任务用 Wireshark GUI 手动筛也能做但数据量一大就非常吃力。脚本加 Wireshark 导出的组合方式能帮你把分析工作变成可复用的工具这是提升调试效率的关键。11. 针对 CAN 协议报文的横向对比协议分析的通用方法论你搜索的时候可能已经注意到“CAN 协议报文解析”和“MQTT 解析”这两个话题经常被一起搜到。这背后其实有一套通用的协议分析方法论搞通了一套就通了另一套。CAN 总线报文分析和 MQTT 最大的不同在于CAN 是基于帧的、无 TCP/IP 层的现场总线Wireshark 直接抓不到需要借助 USB-CAN 适配器把总线数据转入 PC再由工具转成可以被 Wireshark 或专用软件看到的格式。而 MQTT 是基于 TCP/IP 的天然会被 Wireshark 捕获和解析。从方法论的角度看两者都要解决三个问题报文的边界在哪、关键字段是什么、错误码怎么映射。MQTT 里你关注的主题和 QoSCAN 里你关注的是帧 ID 和 DLC、数据字节。你只要掌握了“先看整体帧结构再拆字段最后对照错误语义”这套顺序任何协议报文都不会难倒你。这也是我为什么强烈推荐用 Wireshark 入手学习协议分析的原因——它把协议的每一层都可视化拆开了你会形成一个非常直观的“协议积木”概念。以后再学别的协议上手会快得多。12. 我的实操心得抓包前想清三件事抓包后高效定位最后分享几个我在实际项目里沉淀下来的抓包习惯每一个都是踩坑换来的。第一抓包前想清楚“我要证明什么”。抓包最忌讳“先抓了再说”抓完一大坨数据反而不知道怎么分析。你至少要有一个假设比如“设备应该每 10 秒发一条 PUBLISHQoS 1主题是 xxx”然后抓包去验证这个假设。假设清楚了过滤器怎么设置、抓多久、看哪些字段全都自动明确。第二抓包时一定要记录现场时间。Wireshark 的报文时间戳默认是抓包启动后的相对时间你最好打开“视图” - “时间显示格式” - “日期和时间”这样抓包文件和业务日志才能对齐。否则日志里显示 10:23:45 有异常你抓包文件里却是第 3684 秒还得自己换算白白浪费时间。第三不要把 Wireshark 当成“最后手段”。很多工程师习惯先翻业务日志和代码实在查不出来再抓包。但协议链路的问题抓包往往是最快、最准确的定位方式。拿到问题应该先抓包确认现象看日志佐证方向再去看代码找根因这个顺序能让排查效率翻倍。第四抓包文件记得做好标注。在 Wireshark 里右键一条报文 - “注释分组”写上“123 秒时出现 PUBACK 丢失”之类的现场备注保存 pcapng 文件后这些注释会一直保留。团队协作排障时你的分析结论就一目了然不用每次都从头解释一遍。我每次给团队排障都会打印一张 TCP 报文状态速查表贴在显示器边上。TCP 层如果有大量乱序、重传那问题多半在网络如果在网络没问题的前提下 MQTT 报文异常那问题多半在应用或 Broker 配置。先分网、再分层这是用 Wireshark 排查 MQTT 问题最核心的心法掌握这一条你基本就超过八成的新手了。