Wireshark实战:MQTT报文抓包深度解析与常见问题排查

发布时间:2026/9/18 18:17:45

Wireshark实战:MQTT报文抓包深度解析与常见问题排查 Wireshark实战里MQTT这个协议属于典型的“看着简单抓包才发现门道多”的类型。很多人用MQTTX或者EMQX能跑通收发但一问到QoS级别怎么影响报文交互、遗嘱消息到底什么时候发、Keep Alive的超时机制在包上怎么体现往往就卡住了。这篇我直接接着实战系列的风格从搭建测试环境开始把MQTT最核心的几类报文在Wireshark里的样子、过滤写法、交互时序全部拆开讲一遍最后把我在实际抓包里遇到过的几个典型问题也一并列出来。1. MQTT的协议设计思路与抓包前必须搞懂的几个关键点1.1 为什么MQTT能这么轻轻在哪里MQTT的全称是Message Queuing Telemetry Transport翻译过来就是消息队列遥测传输。很多人一看到“消息队列”四个字就下意识拿它和RabbitMQ、Kafka做对比实际上两者根本不是一回事。MQTT核心解决的问题是低带宽、高延迟、网络不稳定的环境下的设备通信它不会像HTTP那样搞一堆Header也不会像Kafka那样依赖批量吞吐和分区副本。轻主要体现在两个层面。第一个层面是报文本身的体积小一个CONNECT包除了固定协议头核心的ClientID、Keep Alive、Clean Session标志都是紧凑的二进制编码几乎没有冗余字段。第二个层面是交互模型简单客户端和服务器通过一个长连接保持通信发布和订阅被解耦成了两个独立的维度。我在调试STM324G模块接入MQTT服务器的时候代码里发的第一条CONNECT包整个才三十几个字节这在HTTP里面连请求行都写不完。抓包前必须先理解MQTT的报文结构。MQTT控制报文由三部分组成固定报头Fixed Header每个报文都有包含报文类型、标志位、剩余长度。可变报头Variable Header部分报文才有比如CONNECT里有协议名和协议级别PUBLISH里有主题名。有效载荷Payload具体数据内容比如PUBLISH里的消息体SUBSCRIBE里的主题过滤器列表。固定报头第一字节的高四位是报文类型低四位是标志位不同类型的报文对标志位有不同的要求。剩余长度使用的是变长编码方式每个字节的低7位表示数据最高位表示是否还有后续字节所以理论上一字节可以表示0到127超过这个范围就用多字节最多4个字节。这一点在Wireshark里看得很直观——你点击一个PUBLISH报文的Remaining Length字段它能直接给你算出实际长度省得自己手工解码。1.2 发布订阅模型比请求响应模型到底强在哪我们平时最熟悉的HTTP是典型的请求响应模型客户端主动发请求服务器被动回响应两者是强绑定的。但MQTT采用的是发布订阅模型消息的发送方和接收方完全解耦。解耦体现在三个维度空间解耦发布者和订阅者不需要知道对方的存在不需要对方的IP或端口只需要知道一个共同的主题。时间解耦发布者和订阅者不需要同时在线Broker会把消息缓存起来订阅者上线后可以收到离线期间的消息前提是持久会话QoS0。同步解耦发布操作是异步的发布者发完消息就可以干别的不会阻塞等待所有订阅者确认。这三个解耦特性让MQTT特别适合设备数量大、网络不稳定的物联网场景。我在Wireshark里抓包时经常能看到的一个现象是一个PUBLISH报文从设备发出后Broker端马上会返回QoS确认报文PUBACK或者PUBREC但订阅者可能过了很久才上线或者压根不在线。这就是解耦带来的好处——发布者和订阅者之间的生命周期完全独立。1.3 抓包前需要建立的Wireshark过滤清单MQTT的默认端口是1883TLS加密是8883。在Wireshark里最简单的过滤方式是直接输入mqtt或者tcp.port 1883。但如果你的环境中存在大量其他TCP流量建议直接用mqtt过滤协议Wireshark会自动识别并解析。不过有一个坑要注意如果你抓的是回环接口通常是用Mosquitto在本地跑Broker客户端也用本地客户端连接的情况Wireshark默认是能抓到回环流量的但需要确保你选择了正确的接口。Windows下通常叫“Npcap Loopback Adapter”Linux下是lo。很多人在本地测试时用mqtt过滤半天一条包都看不到就是因为接口选错了。另外如果你使用了TLS加密的MQTT连接8883端口Wireshark是识别不出MQTT协议层的只能看到TCP。这时候需要配置SSLKEYLOGFILE或者将Broker端配置成关闭TLS的模式才能看到明文报文。我自己的习惯是先抓明文1883的包理解协议交互再开TLS对照看加密后的差异。2. 完整抓包环境搭建Mosquitto MQTTX Wireshark三板斧2.1 为什么选Mosquitto而不是EMQXEMQX功能强大Web管理界面好看支持规则引擎和插件但我个人在实际抓包分析时更推荐Mosquitto原因很简单它轻量、无Web界面干扰、日志简洁、配置直观而且行为更贴近一个标准的MQTT Broker实现。你用EMQX做生产环境没问题但做协议分析时Mosquitto能让你把注意力集中在报文交互本身而不是被管理后台分散。还有一个重要原因Mosquitto对MQTT 5.0的支持很完整配置项里可以设置allow_anonymous、password_file、persistence等这些参数在验证Wireshark不同报文行为时都非常有用。比如我想验证“遗嘱消息在客户端非正常断开时才会发布”在Mosquitto里直接改配置就能模拟出各种断开场景。如果你已经装了EMQX也没关系抓包层面的分析逻辑完全一样只是我个人习惯而已。2.2 本地Broker的安装与配置以Ubuntu/Debian系统为例安装Mosquitto只需要两行命令sudo apt update sudo apt install -y mosquitto mosquitto-clients安装完成后确认服务是否在运行sudo systemctl status mosquitto如果提示没有启动手动启动一下sudo systemctl start mosquitto默认配置下Mosquitto监听1883端口且允许匿名连接。如果你需要验证用户名密码机制需要手动编辑配置文件/etc/mosquitto/mosquitto.conf添加以下内容allow_anonymous false password_file /etc/mosquitto/passwd生成密码文件的命令是sudo mosquitto_passwd -c /etc/mosquitto/passwd testuser这种方式在验证“用户名密码错误导致连接拒绝”的场景时很好用Wireshark里能看到Broker返回的CONNACK报文携带错误码5。Windows下安装则更简单去官网下载安装包一路Next装完。Windows服务默认也是自动启动的日志路径在C:\Program Files\mosquitto\mosquitto.log具体看安装目录。2.3 客户端选型MQTTX和mosquitto_pub/sub各自适用的场景MQTTX是一款跨平台的图形化客户端支持MQTT 3.1.1和5.0界面友好连接参数配置项齐全非常适合手动控制连接行为来配合抓包。我最喜欢它的一个功能是可以单独发送一条指定Topic、指定QoS、指定Retain标志的消息这在分析PUBLISH报文各种组合标志位时的意义很大。比如我想验证“Retain标志置1的PUBLISH报文长什么样”用MQTTX勾选Retain再发一条Wireshark里立刻就能看到固定报头中Retain位的变化。这种精细控制是Socket工具或者telnet做不到的。mosquitto_pub和mosquitto_sub则是命令行工具适合用脚本批量控制场景。比如用循环连续发100条消息观察TCP层有没有粘包/拆包现象。命令格式如下mosquitto_sub -h 127.0.0.1 -p 1883 -t test/topic -v mosquitto_pub -h 127.0.0.1 -p 1883 -t test/topic -m hello mqtt -q 1-v参数会让sub端打印主题名便于区分不同Topic的消息。-q参数指定QoS级别这个在抓包时非常重要不同QoS级别下的完整报文交互完全不同。2.4 Wireshark抓包预配置打开Wireshark选择回环接口如果你Broker和客户端都在本机或者实际网卡在过滤栏输入mqtt然后抓包。这里有个细节Wireshark对MQTT协议的支持版本有些老版本解析MQTT 5.0报文会有偏差。实测下来Wireshark 3.6及以上版本对MQTT 5.0支持得比较完整能正确解析属性Properties部分如果用的是2.x老版本建议升级否则可读性差很多。另外建议开启Wireshark的“Follow TCP Stream”功能。当你鼠标右键点击任意一条MQTT报文选择“Follow - TCP Stream”能看到这一整条TCP连接上的全部MQTT报文序列。这个视角在分析一次完整的连接建立、订阅、发布、心跳、断开的生命周期时特别有用比一条条报文翻效率高得多。抓包过程中还要注意如果MQTT消息的数据量很大Wireshark的实时刷屏会拖慢界面。可以在抓包前设置一个抓包停止条件比如抓1000个包自动停止或者用-a duration:60方式在命令行模式下抓60秒。命令行抓包的写法tshark -i lo -f tcp port 1883 -w mqtt_test.pcapng -a duration:60这样可以避免打开图形界面占用过多内存适合长时间抓包场景。停止后把pcapng文件用Wireshark打开来分析体验比实时抓包好很多。3. 抓包实战核心报文交互的Wireshark深度解析3.1 CONNECT/CONNACK握手过程到底交换了什么先用MQTTX连接本机Broker同时Wireshark抓包连接成功后停止抓包会话里至少应该有两条报文客户端发出的CONNECT和服务器回应的CONNACK。CONNECT报文的固定报头第一个字节是0x10。0x10这个数字的二进制是0001 0000高四位0001表示报文类型是1CONNECT低四位0000是CONNECT要求必须为零的标志位。可变报头里的第一个字段是协议名正常情况下是“MQTT”四个ASCII字符0x00 0x04 0x4D 0x51 0x54 0x54Wireshark会直接显示成字符串。协议级别字段MQTT 3.1.1是0x04MQTT 5.0是0x05。连接标志位这一个字节信息量很大。Clean Session或者MQTT 5.0里的Clean Start位置1表示客户端要求一个全新的会话Broker端不保存任何历史状态。如果置0Broker需要恢复之前该ClientID的会话状态。Will Flag位置1说明这条连接带遗嘱消息遗嘱的Topic和Payload在CONNECT报文后续部分直接携带这让CONNECT包在抓包时看起来比想象中要长。Keep Alive字段占两个字节单位是秒。设成60表示Broker要在60秒内至少收到一次客户端的心跳PINGREQ否则判定连接超时。实际抓包时你会发现MQTT的心跳机制和TCP的Keep-Alive是两码事MQTT的心跳是应用层主动发PINGREQTCP Keep-Alive是内核层面的探测包两者不要搞混。CONNACK报文的固定报头第一字节是0x20连接确认标志位Session Present在可变报头里。最关键的是返回码字段返回码含义0连接已被接受1服务器拒绝不支持的协议版本2客户端标识符合法但服务器拒绝连接3服务器不可用4服务器拒绝用户名或密码错误5服务器拒绝未授权如果CONNACK返回码不是0说明握手失败。我在实际环境中遇到最多的就是返回码5——Broker配置了allow_anonymous false但客户端没有传用户名密码。这个错误在Wireshark里一眼就能看出来不需要看服务器日志。3.2 PUBLISH报文与QoS 0/1/2的完整交互差异发布消息时的核心报文是PUBLISH固定报头第一字节是0x30加上各种标志位。低四位中DUP标志表示是否重发QoS标志占两位Retain标志表示是否保留消息。QoS 0第一字节是0x30没有报文标识符Packet Identifier可变报头里只有主题名和负载。接收方收到即处理不回复任何确认这是最轻量的模式。QoS 1第一字节是0x32带报文标识符Broker处理完成后回复PUBACK确认。如果客户端在一定时间内没收到PUBACK会重发这条PUBLISHDUP标志置1。QoS 2第一字节是0x34带报文标识符但交互过程变成四次握手PUBLISH - PUBREC - PUBREL - PUBCOMP。这保证了消息恰好被送达一次代价是报文交互数量翻倍。从Wireshark看QoS 1的交互过程你会在抓包结果里看到一对PUBLISH和PUBACK报文它们的Packet Identifier是相同的。QoS 2则复杂一些一条消息要经历四轮交互中间差点看不出是同一批消息的关联。Wireshark实际上不提供自动关联同一Packet Identifier的一组报文需要靠自己的眼睛和过滤规则来追踪。我用mqtt mqtt.msgtype 3过滤出所有PUBLISH报文再找出它们的Packet Identifier从Wireshark的Packet Details面板里找到Message Identifier字段。然后再用mqtt mqtt.msgtype 4过滤出所有PUBACK对比两者的Message Identifier是否一致。这个手工对照的过程虽然繁琐但对理解MQTT QoS机制却非常有帮助。当消息体比较大时Wireshark里还会出现一个现象单条MQTT消息跨越了多个TCP分段。比如一条2KB的PUBLISH消息在Wireshark的报文列表里显示为多行TCP协议只有最后一行的解码标签里才是MQTT。这时候需要用Wireshark的“Assemble fragmented TCP messages”功能或者直接点开协议解析它会在Info列提示[TCP segment of a reassembled PDU]点进去能看到组包后的MQTT内容。我踩过一次坑用脚本往MQTT里发了一条10KB的数据Wireshark过滤mqtt死活看不到这条消息看了半天才发现消息被拆在了好几个TCP包里Wireshark默认的显示过滤对“被TCP分片的MQTT报文”不会在首行标记为MQTT。解决办法是把过滤条件改成mqtt || tcp.port 1883再通过“Follow TCP Stream”查看完整内容。3.3 SUBSCRIBE/SUBACK订阅时的过滤器是如何编码的SUBSCRIBE报文固定头第一字节是0x82这里的0x8是报文类型8低四位中的0x2是必须设置的保留位。可变报头里有一个Packet Identifier然后是一系列主题过滤器。每个主题过滤器由主题字符串QoS级别组成。比如订阅test/topic且QoS为1那有效载荷就是主题长度2字节主题ASCII QoS级别1字节。Wireshark对SUBSCRIBE报文的解析非常友好它会把订阅的Topic和QoS等级直接展开在Packet Details面板里不需要人工解码。与之对应的响应是SUBACK报文固定头第一字节是0x90里面携带返回码数组。返回码0表示成功且最大QoS为01表示成功且最大QoS为12表示成功且最大QoS为20x80表示失败。这里有个容易忽略的细节SUBSCRIBE报文里的QoS表示“这个订阅允许的最大消息QoS上限”而Broker实际下发的消息QoS是取“发布时的QoS”和“订阅时的QoS”中较小的那个。比如发布者用QoS 2发布订阅者用QoS 0订阅那么订阅者实际收到的是QoS 0消息。在Wireshark里看这个过程你会看到Broker发出的PUBLISH报文的QoS标志是0而不是2。刚开始抓包时我以为Broker出BUG了后来才明白这是QoS降级机制。3.4 PINGREQ/PINGRESP和DISCONNECT连接保活与自我结束MQTT的Keep Alive机制是靠PINGREQ和PINGRESP这对报文实现的。Keep Alive时间在CONNECT包里设置Broker计算这个时间的一半作为“半程心跳”参考如果超过Keep Alive时间没收到任何控制报文就断开连接。抓包时如果你设置Keep Alive为60秒你会看到客户端每30到45秒左右发一条PINGREQBroker秒回PINGRESP。Wireshark对这两个报文的解析非常简单PINGREQ固定头是0xC0PINGRESP是0xD0两者都没有可变报头也没有有效载荷。注意在实际抓包时Wireshark并不计算“距离上一包已经过了多少时间”这样的统计字段你需要自己看Time列的时间差。我在排查设备频繁离线问题时就是通过Time列观察到PINGREQ的间隔不规律有的间隔甚至超过60秒最终定位到是蜂窝网络信号差导致的上行数据无法及时送达。DISCONNECT报文固定头是0xE0由客户端发送给Broker表示正常断开连接。这里关键区别在于正常断开时携带遗嘱消息的会话Clean Session0且Will Flag1Broker不会把遗嘱消息发布出去。只有非正常断开——比如网线断开、TCP连接超时、进程崩溃——Broker才会发布遗嘱消息。这个逻辑在抓包时需要专门构造场景去验证。4. 高级场景遗嘱消息、Retain与会话恢复的抓包验证4.1 遗嘱消息的完整触发与观察流程遗嘱消息是MQTT里很多人容易搞混的一个特性。我的经验是只有把它放在抓包场景里完整跑一遍才能彻底理解。具体验证步骤在MQTTX中新建两个连接。连接A用于发布遗嘱消息连接B用于订阅遗嘱主题。先在连接B中订阅遗嘱Topic比如will/test确保后续遗嘱发布时能被捕获。在连接A的配置中勾选Will选项设置遗嘱Topic为will/test遗嘱Payload为“client A offline”QoS选1。连接A建立连接后在Wireshark里能看到CONNECT报文的可变报头和Payload部分比普通连接多出了Will Topic和Will Message字段。这是遗嘱消息的“注册”阶段。关键操作断开连接的方式很重要。如果点击MQTTX的“断开”按钮会正常发送DISCONNECT报文此时Broker不会发布遗嘱消息。要触发遗嘱生效必须把连接A的网络直接掐断。最简单的方法是在Wireshark里选择对应的TCP连接然后用tcp.rst或者直接关闭MQTTX进程。掐断连接后观察连接B是否收到遗嘱消息。从抓包角度看当连接A被强制断开后TCP层会看到RST或者多次重传直至超时。稍后Broker会向连接B发送一条PUBLISH报文Topic是will/testPayload是预设内容。这条PUBLISH报文就是遗嘱消息。我在这个验证过程中踩过的最大的坑是用正常断开方式去触发遗嘱消息结果怎么都等不到遗嘱。后来才明白正常断开时客户端会发DISCONNECTBroker根据MQTT协议规范会丢弃遗嘱消息。协议文档里写得很清楚遗嘱消息只有在连接被异常中断时才会发布。4.2 Retain标志Broker缓存与重发机制Retain标志位决定Broker是否保留这条消息的最新值。当你用Retain标志发布一条消息后新订阅该Topic的客户端会立刻收到这条消息而不是等发布者再次发布。抓包验证的方式很简单在MQTTX中发布一条消息到retain/test勾选Retain选项。断开连接A再让一个新客户端连接并订阅retain/test。观察Wireshark你会发现订阅后Broker立刻向这个新客户端推送了一条PUBLISH报文Payload正是之前发布的内容。实际场景中这个特性非常有用。比如设备状态上报设备挂掉之前发一条Statusoffline且Retain的数据这样任何客户端订阅这个Topic时都能立刻知道当前状态而不需要等设备重新上线。注意Retain标志和遗嘱消息叠加使用会产生一个很常见的模式设备连接时设置遗嘱消息为“离线状态”并规定Retain为1这样一旦设备异常断开Broker会发布并保留“离线状态”任何新订阅者都能立刻看到。这个组合在设备状态监控场景里几乎是标配但它对Broker存储也带来额外开销。4.3 持久会话与离线消息的报文差别支持离线消息需要两个条件连接时Clean Session设置为0或MQTT 5.0的Clean Start为0且消息QoS大于0。这两者缺一不可。抓包观察时你会发现一个有意思的现象同一台Broker上Clean Session1的连接断开后再次连接时CONNACK报文的Session Present标志为0表示服务端没有恢复任何会话状态。而Clean Session0的连接断开后重新连接CONNACK的Session Present可能为1表示服务端恢复了一个持久会话。离线消息的补发在Wireshark里看得更加直观客户端上线后Broker会主动推送一批PUBLISH报文Payload是离线期间的消息并且这些消息的QoS级别和发布时一致。我见过有人误以为离线消息只有在重新订阅时才能收到其实只要会话还在Broker会根据订阅关系自动补发。有一点值得注意持久会话对Broker内存的占用是持续性的如果ClientID固定但用户不再上线这些会话会一直占用服务器资源。生产环境要设置合理的会话过期时间。5. 实战中常见的Wireshark抓包问题与Wireshark排查思路5.1 为什么抓不到任何MQTT报文这是我在答疑群里被问到最多的问题。排查看三个地方抓包接口选错了。如果你Broker和客户端都在本机必须选回环接口不是以太网或WLAN。检查方法确认Broker日志里的IP是127.0.0.1还是局域网IP。过滤条件写错了。注意MQTT协议名在Wireshark里是小写mqtt不是大小写不敏感。另外如果是WS-MQTT走WebSocket的MQTTWireshark需要解析WebSocket之后才能解码出MQTT这时候单写mqtt可能看不到。报文被TLS加密了。如果你客户端连接的是8883端口Wireshark无法识别出MQTT协议只会显示TLSv1.2。可以先抓明文1883的包验证问题再去处理TLS解密的问题。另外在Windows下还有一个常见坑Wireshark安装时没有勾选安装Npcap或者Npcap版本太旧导致无法抓回环流量。重装Npcap后回环接口才会出现在接口列表里。5.2 Wireshark明明显示TCP包为什么不是MQTT这个问题的常见诱因是TCP粘包和分包。MQTT建立在TCP之上TCP是流式协议。当大量MQTT消息在短时间内连续发出时底层TCP很可能将多条MQTT消息合并到同一个TCP段中发送这就是粘包。这时候Wireshark解析第一条MQTT消息后后续数据会在同一个TCP段里继续解析你会看到同一个TCP段下面带多个MQTT报文。反过来如果MQTT消息很大比如超过MSS底层TCP会把一条MQTT消息拆成多个TCP分段发送Wireshark在首行不会识别成MQTT协议只会显示TCP。这时候你要么启用TCP重组默认是开启的要么就手动拼接分段内容来看。我的习惯是在Wireshark的Preferences - Protocols - TCP里确认“Allow subdissector to reassemble TCP streams”这个选项是开启的。如果某些分析场景必须关闭重组那就要接受报文的边缘情况。5.3 QoS 2交互过程中出现重复报文是不是Broker的BUGQoS 2设计目标就是防止消息重复投递但你抓包时可能发现在PUBLISH、PUBREC、PUBREL、PUBCOMP的交互过程中有时候同一Packet Identifier消息会重复发送。这在协议设计里是允许的。举例来说客户端发送PUBLISH后如果一直没有收到Broker的PUBREC客户端会重发PUBLISH且DUP标志置1Packet Identifier与首次发送时一致。如果此时Broker已经成功收到并回复PUBREC但回复包在网络上丢了Broker收到重发的PUBLISH时会判断Packet Identifier然后直接回复PUBREC而不会再次存储消息。在Wireshark里定位这类重复报文比较繁琐因为MQTT的报文标识符不是全局唯一的不同连接间可以复用。所以分析时一定要绑定到具体的TCP流里看不能只看一个Packet Identifier就判断是重复包。我的经验是用Wireshark的“Follow TCP Stream”把完整四步协议过程拉出来再对着协议规范逐条对应。如果不方便可以在过滤栏输入mqtt mqtt.packetid N配合点击具体流逐个排查。5.4 大消息被截断只显示520字节或2090字节Wireshark默认在抓包完成前不会直接告诉你但当你点击一条大的PUBLISH报文后Packet Details面板里能看到这个包的实际数据长度。如果你只看到“520 bytes”或“2090 bytes”这样的截断数据多半是抓包时的快照长度Snaplen设置过小。Wireshark默认Snaplen是262144字节一般情况不会截断。但如果你手动调小了快照长度或者使用tcpdump时指定了-s 128之类的小快照长度就会出现截断情况。解决方法是重新抓包抓包时把Snaplen设为0表示不截断或者直接使用默认值。另外“Wireshark为什么只显示520字节数据”还有一种情况消息本身不大但Wireshark的Decode As功能没有自动识别成MQTT导致解析器把MQTT数据当作未知数据展示。可以右键点击该报文选择“Decode As”然后将TCP端口1883对应的协议改成MQTT重新解析。5.5 Keep Alive超时导致设备掉线怎么从抓包上定位当设备莫名其妙掉线时抓包是最有效的排查手段。步骤抓到设备掉的时段的流量过滤mqtt || tcp.port 1883。看近一分钟内有没有PINGREQ发出。正常情况下每个Keep Alive周期内至少会有一条PINGREQ和一条PINGRESP。如果客户端发出PINGREQ但Wireshark里看不到PINGRESP说明Broker没有响应或者响应超时。这时候要看TCP层有没有重传。如果连PINGREQ都没发出说明客户端的应用层卡死或者定时器异常问题大概率在固件代码里不在网络上。我在STM324G模块的场景中踩过几次坑最后定位到是模块的TCP连接被基站侧回收了但固件不知道还保持着MQTT会话状态。这时固件发的PINGREQ实际上在空口层就丢了Wireshark里看只有一个单独的PINGREQ没有对端响应随后就是TCP重传风暴。这种情况下靠MQTT的心跳机制已经来不及了必须依赖MQTT协议层面的网络诊断为更底层的断线检测。6. 过滤技巧与高效分析的三个实用经验用到最后再分享三个Wireshark实操技巧这几条是我在真实项目里反复用到的。第一是学会用显示过滤表达式快速定位特定行为。想只看CONNECT和CONNACK报文输入mqtt.msgtype 1 || mqtt.msgtype 2。账号密码错误导致连接失败先过滤mqtt.msgtype 2再看返回码字段。想看所有发布消息过滤mqtt.msgtype 3想追踪某个Topic过滤mqtt.topic test/topic。第二是善用Wireshark的“Follow TCP Stream”按流分析功能。MQTT虽然报文种类多但只要跟着TCP流一条条看协议交互逻辑会非常清晰。我在排查一个“订阅后收不到消息”的问题时发现订阅成功SUBACK返回码为0但Broker就是不向客户端发PUBLISH。后来跟了一遍TCP流才发现这个客户端在旧连接上订阅的是一个Topic实际上消息发到另一个Topic了纯粹是订阅关系配错了。第三是搭建测试环境来复现特定场景。Wireshark抓包解决不了所有问题但它能帮你把问题范围缩小。我现在的做法是先根据现象构造一个最小化环境本地Mosquitto MQTTX然后在抓包里复现逐一排除。真正常见的MQTT问题十有八九是QoS设置不对、Topic不匹配、Clean Session理解错误这些在抓包面前都藏不住。Wireshark在MQTT调试中的角色更像是一个“眼见为实”的帮手。纸上谈兵式的协议分析远远不够只有亲手抓到CONNECT、SUBSCRIBE、PUBLISH、PUBACK、PINGREQ这些报文才能对MQTT的行为建立一个直觉认知。遇到设备消息丢了、订阅收不到、掉线频繁这类问题时条件反射地抓起包看一眼通常比漫天瞎猜定位得更快。
延伸阅读

更多相关文章

2026/9/18 18:12:45

Docker与K8s关系全解:从容器镜像到K8s编排落地实战

先把一个常见误区摆到台面上:很多人刚接触容器技术时,会把 Docker 和 Kubernetes(下称 K8s)当成“二选一”的竞品,甚至在群里问“现在都上 K8s 了,Docker 是不是要被淘汰了”。这个问题我这些年被问过不下几…

2026/9/18 18:12:45

Windows批量重命名实战:cmd与PowerShell双方案精解

1. 为什么批量重命名这件事,值得你花20分钟认真读完Windows系统下批量重命名文件,听起来像个小技巧,但实际工作中它可能是你每天节省15分钟、避免3次手抖误操作、防止1次关键文件名错乱导致后续流程中断的底层能力。我做过6年IT支持、带过4届…

2026/9/18 18:12:45

太阳光不同波段如何一步步损伤皮肤?从UVA到红外线的全解析

太阳光里的“隐形刀”:不同波段怎么一点点毁掉你的皮肤我做了这么多年皮肤相关的研究和科普,最常被问到的一个问题就是:“我明明防晒了,为什么还是长斑、长皱纹、皮肤变差?”每次听到这种问题,我都想把人拉…

2026/9/18 19:22:55

运营报表数据异常自动分析与归因解释

运营报表数据异常自动分析与归因解释在很多企业的日常运营中,数据大盘每天都会发生各种波动:日活(DAU)突然下跌 15%、特定渠道的转化率骤降、退款率在某个时间段异常升高。 传统的做法是运营发现异常后,在群里艾特数据…

2026/9/18 19:22:55

基于YOLOv8与PyQt5的路面坑洞检测系统实战

1. 路面坑洞检测系统整体设计思路拆解1.1 为什么选择YOLOv8而不是传统图像处理方法做路面坑洞检测这件事,我最早试过用传统的边缘检测加阈值分割。OpenCV的Canny算子配合形态学操作,在光照均匀、坑洞边缘清晰的理想图片上确实能跑出结果,但一…

2026/9/18 19:22:55

维护者的情绪管理:面对恶意差评与无理索取

维护者的情绪管理:面对恶意差评与无理索取开源是一件充满理想主义色彩的事情,但只要你的项目获得了一定的曝光,你的 GitHub Issue 区就不可避免地会变成各种情绪的聚集地。 有的用户会因为一个微小的 Bug 在评论区破口大骂:“这么…

2026/9/18 19:22:55

轻量鉴权:基于 HMAC 签名的 API 认证

轻量鉴权:基于 HMAC 签名的 API 认证在构建微服务间通信、外部 Webhook 回调或轻量单体系统对外开放的 API 时,很多团队一上来就照搬复杂的 OAuth2、IdentityServer 或者是带有一堆配置的 JWT 刷新体系。 对于简单的服务端对服务端(S2S&#…

2026/9/18 19:22:55

C-NCAP 2024附录L详解:AEB/FCW测试时间基准与ADAS工程实践

简介:C-NCAP 2024版附录L是面向整车企业ADAS开发与测试工程师、安全评价人员及高校研究者的主动安全试验规程。文档完整规定了AEB、FCW等系统的试验术语、车辆坐标系、天气要求、VUT准备与预处理流程,并系统展开L.6.1的AEB C2C测试场景,如CCR…

2026/9/18 19:17:55

硬件工程师的硬核读法:如何用四层过滤法精读芯片资料

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/18 14:13:01

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/18 0:01:09

Google Colab 实战:运行模型、数据加载与报错排查

1. 为什么我劝你先搞懂 Colab 的运行模型1.1 Colab 到底是什么,跟本地跑代码差在哪Google Colab 简单说就是一台跑在浏览器里的 Linux 虚拟机,你打开一个 Notebook,背后就连上了一台带 GPU 的远程机器。你在单元格里敲的每一行 Python&#x…

2026/9/18 0:01:09

C语言数据类型与表达式详解

1. C语言数据与数据类型概述在C语言编程中,数据是程序处理的核心对象。理解数据的分类和特性是掌握C语言的基础。C语言中的数据主要分为四大类:常量、变量、表达式和函数。这些数据类型构成了C语言程序的基本元素,每种类型都有其独特的特性和…

2026/9/18 0:01:09

SQL时间字段指定时间段查询:区间语义、索引与时区避坑

上周排查一个线上问题&#xff0c;用户反馈"昨天的订单一条都没查到"&#xff0c;但数据库里明明躺着两千多条。最后定位下来&#xff0c;不是数据丢了&#xff0c;也不是接口挂了&#xff0c;而是那个查询条件把时间段写成了> 2024-05-20 00:00:00 AND < 2024…

2026/9/18 14:13:03

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行&#xff0c;Type-C接口算是典型的“看着简单&#xff0c;做起来全坑”的东西。光引脚就24个&#xff0c;高低速信号、电源、控制线全部塞在一个小小的连接器里&#xff0c;如果PCB布局不做规划&#xff0c;打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/18 14:13:02

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/18 14:13:02

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码