侧边栏壁纸
  • 累计撰写 46 篇文章
  • 累计收到 2 条评论

用Python写MQTT订阅端碰到的漏消息坑

2026-9-30 / 0 评论 / 4 阅读

用Python写MQTT订阅端碰到的漏消息坑

上周三蹲在实验室工位调温湿度传感器的上报脚本,终端里跑着我半小时前顺手写的paho-mqtt订阅代码,抬头看传感器屏幕明明已经跳了三次数值,终端里只打出来1条消息。

最开始我以为是代码写漏了

上来就瞎改了快一小时,走的弯路现在想想都好笑:

  • 先是怀疑on_message回调里的打印逻辑阻塞,把所有数据入库、阈值判断的代码全注释掉,只留一行print输出,跑了一会还是偶发漏消息
  • 又蹲在交换机旁边ping了十来分钟MQTT服务器地址,延迟稳得很,根本看不到网络丢包的痕迹
  • 甚至拆了两个传感器拿USB转串口直连读上报日志,串口里的数据整整齐齐按固定间隔出,半条都没缺,那会我都准备给传感器厂商提bug工单了

翻源码才找到问题根源

后来搜问题的时候翻到paho-mqtt的官方文档,又对着自己那几行抄来的示例代码逐行对,才发现好几个低级错误凑一块了。最开始的代码我写得特别随意:

import paho.mqtt.client as mqtt
client = mqtt.Client(client_id="temp_sensor_sub")
client.connect("192.168.3.12", 1883, 60)
client.subscribe("sensor/temp/#", qos=1)
client.loop_forever()

几个坑全踩中了:第一是默认的clean_session参数开着,客户端只要断开重连,broker就会直接清空会话,离线期间的消息全丢;第二是我把client_id写死成了"temp_sensor_sub",当时电脑上开着个临时测试脚本,楼上服务器上还跑了个同id的订阅端,两个客户端互相踢下线,broker每次只给最后上线的端发消息,当然会漏;第三是我没在连接回调里写订阅逻辑,有时候无线网闪断重连之后,订阅关系没恢复,自然收不到消息。

对应改起来其实没几行代码,核心配置记下来就行:

  1. 先调整客户端初始化参数,固定唯一client_id,关闭clean_session开启持久会话,让broker能保留客户端离线期间的消息:
    client = mqtt.Client(
        client_id="lab_temp_sub_pc_01",
        clean_session=False
    )
  2. 把订阅逻辑写到on_connect回调里,不管是首次连接还是断网重连,连接成功后都会自动重新订阅,避免重连后丢订阅:
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            client.subscribe("sensor/temp/#", qos=1)
            print("连接成功,已完成主题订阅")
    client.on_connect = on_connect
  3. 订阅端和发布端的QoS等级要匹配,要是发布端用QoS0发消息,就算订阅端设成QoS2也存不住离线消息,这点很容易忽略。
提个醒:如果用的是公共测试MQTT broker就别开持久会话了,公共服务器一般会限制会话保留时长,而且client_id很容易和其他用户撞,到时候莫名被踢下线都找不到原因。

改完这几行配置我把脚本扔到实验室的小服务器上挂到现在,再也没出现过漏收的情况。说起来平时总觉得MQTT调用简单,抄两行示例就能跑,真要稳当用还真得把每个参数的默认值摸清楚。

评论一下?

OωO
取消