如何让Paho-MQTT循环实现超时退出?
如何让Paho-MQTT循环实现超时退出?
这个问题我之前也遇到过!核心问题出在time.sleep(5)的无条件阻塞上,还有主线程和MQTT循环线程的同步问题。咱们一步步拆解:
原代码的问题分析
- 当你调用
mqttc.loop_start()时,Paho会启动一个后台子线程来处理MQTT的消息收发、心跳等逻辑。 - 主线程执行到
time.sleep(5)时,会进入无条件的阻塞等待——哪怕后台线程已经收到消息并调用了loop_stop(),主线程还是会老老实实等够5秒才会继续往下走,这就是为什么你明明收到了消息,却还是要等5秒才输出Complete!。 - 如果直接删掉
time.sleep(5),主线程会立刻走到logging.info('Complete!')然后整个程序退出,这时候后台的MQTT循环线程还没来得及完成连接、订阅、接收消息的流程,自然收不到任何消息。
最优解决方案:用线程事件(Event)同步
我们可以用Python的threading.Event来实现主线程和MQTT线程的同步:
- 创建一个事件对象,主线程等待这个事件被触发,超时时间设为5秒。
- 当收到MQTT消息时,在回调函数里触发事件,同时停止MQTT循环。
- 主线程如果在5秒内等到事件触发,就立即结束;如果超时没触发,也会自动结束。
修改后的完整代码
import paho.mqtt.client as mqtt import logging import threading def on_message(client, userdata, message): logging.info(f"Received message: {message.payload}") client.loop_stop() # 触发事件,通知主线程可以结束等待 userdata.set() logging.basicConfig(level=logging.DEBUG, format="%(asctime)s [%(levelname)s] %(message)s") # 创建事件对象,作为userdata传给MQTT客户端 event = threading.Event() mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, userdata=event) mqttc.enable_logger() mqttc.on_message = on_message mqttc.connect("mqtt.eclipseprojects.io") mqttc.subscribe("#") mqttc.loop_start() # 主线程等待事件,超时5秒 if event.wait(5): logging.info("Received message, exiting early!") else: logging.info("No message received within 5 seconds, timing out!") logging.info('Complete!')
效果验证
收到消息的场景
输出会像这样,收到消息后立即结束等待,不会再卡5秒:
2025-01-28 01:45:12,123 [DEBUG] Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'' 2025-01-28 01:45:12,123 [DEBUG] Sending SUBSCRIBE (d0, m1) [(b'#', 0)] 2025-01-28 01:45:12,245 [DEBUG] Received CONNACK (0, 0) 2025-01-28 01:45:12,246 [DEBUG] Received SUBACK 2025-01-28 01:45:12,246 [DEBUG] Received PUBLISH (d0, q0, r1, m0), 'AhoyDTU0600-Streusser/version', ... (6 bytes) 2025-01-28 01:45:12,246 [INFO] Received message: b'0.8.83' 2025-01-28 01:45:12,246 [INFO] Received message, exiting early! 2025-01-28 01:45:12,246 [INFO] Complete!
超时未收到消息的场景
刚好等满5秒后自动退出:
2025-01-28 01:46:00,111 [DEBUG] Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b'' 2025-01-28 01:46:00,111 [DEBUG] Sending SUBSCRIBE (d0, m1) [(b'#', 0)] 2025-01-28 01:46:00,232 [DEBUG] Received CONNACK (0, 0) 2025-01-28 01:46:00,233 [DEBUG] Received SUBACK 2025-01-28 01:46:05,234 [INFO] No message received within 5 seconds, timing out! 2025-01-28 01:46:05,234 [INFO] Complete!
备注:内容来源于stack exchange,提问作者Elliott B
相关产品推荐
相关产品推荐

