
上周三蹲在实验室工位调温湿度传感器的上报脚本,终端里跑着我半小时前顺手写的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每次只给最后上线的端发消息,当然会漏;第三是我没在连接回调里写订阅逻辑,有时候无线网闪断重连之后,订阅关系没恢复,自然收不到消息。
对应改起来其实没几行代码,核心配置记下来就行:
- 先调整客户端初始化参数,固定唯一client_id,关闭clean_session开启持久会话,让broker能保留客户端离线期间的消息:
client = mqtt.Client( client_id="lab_temp_sub_pc_01", clean_session=False ) - 把订阅逻辑写到on_connect回调里,不管是首次连接还是断网重连,连接成功后都会自动重新订阅,避免重连后丢订阅:
def on_connect(client, userdata, flags, rc): if rc == 0: client.subscribe("sensor/temp/#", qos=1) print("连接成功,已完成主题订阅") client.on_connect = on_connect - 订阅端和发布端的QoS等级要匹配,要是发布端用QoS0发消息,就算订阅端设成QoS2也存不住离线消息,这点很容易忽略。
提个醒:如果用的是公共测试MQTT broker就别开持久会话了,公共服务器一般会限制会话保留时长,而且client_id很容易和其他用户撞,到时候莫名被踢下线都找不到原因。
改完这几行配置我把脚本扔到实验室的小服务器上挂到现在,再也没出现过漏收的情况。说起来平时总觉得MQTT调用简单,抄两行示例就能跑,真要稳当用还真得把每个参数的默认值摸清楚。
评论一下?