Python 3.7与Mosquitto本地MQTT通信故障排查求助
从你提供的Mosquitto日志和Python代码来看,核心问题是Python客户端成功连接Broker后,约70秒就因Socket错误被断开——而控制台订阅功能正常,说明Broker本身、网络链路都没有问题,问题大概率出在Python客户端的代码逻辑上。下面给你拆解具体排查方向和修复方案:
1. 最可能的原因:缺少客户端循环机制
你的代码只调用了connect()方法,但paho-mqtt客户端是异步非阻塞的,connect()执行后并不会维持连接。Mosquitto Broker默认会每60秒发送心跳包检测客户端状态,如果客户端没有响应(因为没有运行网络循环处理心跳),Broker会在10秒超时后断开连接——这正好对应你日志里从连接到断开的70秒间隔。
修复方案:在connect()之后启动客户端循环,有两种常用方式:
- 如果你不需要同时执行其他任务,用阻塞式的
loop_forever():# -*- coding: utf8 -*- import paho.mqtt.client as mqtt mqttTopic = 'RaspberryPi1/SMS_Daemon' def connect_msg(client, userdata, flags, rc): # 注意:paho要求on_connect回调必须接收这4个参数,否则会触发异常 print(f"Connected to broker, result code: {rc}") # 可以在这里顺便订阅目标主题 client.subscribe(mqttTopic) def publish_msg(client, userdata, mid): # on_publish回调必须接收这3个参数 print(f"Message published, message ID: {mid}") mqttClient = mqtt.Client(client_id='SMS_Daemon') mqttClient.on_connect = connect_msg mqttClient.on_publish = publish_msg # 显式设置心跳超时为60秒,和Broker默认配置对齐 mqttClient.connect("192.168.0.1", 1883, 60) # 启动阻塞式循环,维持连接并处理消息/心跳 mqttClient.loop_forever() - 如果需要同时运行其他业务逻辑,用后台线程式的
loop_start():# 连接代码同上... mqttClient.connect("192.168.0.1", 1883, 60) # 启动后台循环线程 mqttClient.loop_start() # 这里可以添加你的其他业务代码,比如定时发布消息 while True: mqttClient.publish(mqttTopic, "test message") time.sleep(5)
2. 次要排查点:回调函数参数不匹配
你原代码中的connect_msg和publish_msg没有遵循paho-mqtt的回调函数参数规范,这会导致回调触发时抛出异常,进而可能间接导致客户端崩溃断开。paho对每个回调都有固定的参数签名,必须严格遵守。
比如:
on_connect必须接收client, userdata, flags, rc四个参数on_publish必须接收client, userdata, mid三个参数
如果参数缺失,即使客户端能连接,后续回调触发时会报错,甚至导致进程退出。
3. 可选排查:Broker版本兼容性
虽然你使用的Mosquitto 1.4.15(Ubuntu)和1.5.7(Raspberry Pi)差异不算大,但可以显式指定MQTT协议版本来确保兼容:
# 指定使用MQTT 3.1.1协议,兼容绝大多数Broker版本 mqttClient = mqtt.Client(client_id='SMS_Daemon', protocol=mqtt.MQTTv311)
总结
优先修复客户端循环缺失和回调参数不匹配这两个问题,基本就能解决连接断开的问题。如果问题依旧,可以检查Python的paho-mqtt版本是否过旧,执行pip install --upgrade paho-mqtt更新到最新版再测试。
内容的提问来源于stack exchange,提问作者Geht Euchnixan

