You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Paho-MQTT客户端断开代码16后无法重连问题求助

Paho-MQTT客户端长时间运行后因MQTT_ERR_KEEPALIVE(16)断开且无法重连的问题

问题描述

使用Python Paho-MQTT客户端(已简化脚本逻辑与数据库访问代码),客户端运行数小时后会以错误码16(MQTT_ERR_KEEPALIVE)断开连接,之后进入无限重连循环但无法成功(未收到CONNACK)。

客户端代码

import json
import logging
import time

from paho.mqtt import client as mqtt

logging.basicConfig(level=logging.INFO)
mqtt_logger = logging.getLogger("MqttCon")


def on_connect(client, userdata, flags, rc):
    mqtt_logger.info("Device connected with result code: " + str(rc))
    client.subscribe("some_topic/#", qos=0)


def on_disconnect(client, userdata, rc):
    mqtt_logger.info("Device disconnected with result code: " + str(rc))


def pub_values(client, base_topic, values):
    msg = json.dumps(values)
    target_topic = base_topic
    mqtt_logger.info("Sending message to wheel...")
    client.publish(target_topic, msg, qos=0)


def on_message(client, userdata, msg):
    """
    Input messages format (can be one or list):
    {
        "tag_id": "string",
        "value": "int or float",
        "timestamp": "string format YYYY-MM-DDTHH:MM:SS.F"
    }
    """
    try:
        info = json.loads(str(msg.payload.decode("utf-8")))
        mqtt_logger.info(msg.topic)
        pub_msg = {"tag_ids": [], "timestamp": ""}
        mqtt_logger.info(f"Received message topic is {msg.topic}")
        if isinstance(info, list):
            # some logic
        else:
            # some logic, writing values to InfluxDB
        pub_values(client=client, base_topic="some_topic", values=pub_msg)
    except Exception as e:
        mqtt_logger.error(str(e))


def on_log(client, userdata, level, buf):
    mqtt_logger.info(f"SYSTEM: {buf}")


if __name__ == "__main__":
    client = mqtt.Client(protocol=mqtt.MQTTv311)
    client.on_connect = on_connect
    client.on_disconnect = on_disconnect
    client.on_message = on_message
    client.on_log = on_log
    client.connect_async('<my_mqtt_url>', port=1883)

    client.loop_start()
    try:
        while True:
            time.sleep(0)
    except KeyboardInterrupt:
        pass
    finally:
        mqtt_logger.warning("Stopping client")
        client.loop_stop()
        client.disconnect()

断开时的日志信息

INFO:MqttCon:Received message topic is telemetry/MESPIV/batch
INFO:MqttCon:Sending message to wheel...
INFO:MqttCon:SYSTEM: Sending PUBLISH (d0, q0, r0, m4228), 'b'router/newdata'', ... (11336 bytes)
INFO:MqttCon:Sending message to wheel...
INFO:MqttCon:SYSTEM: Sending PUBLISH (d0, q0, r0, m4229), 'b'router/newdata'', ... (11336 bytes)
INFO:MqttCon:Device disconnected with result code: 16
INFO:MqttCon:Device disconnected with result code: 16
INFO:MqttCon:SYSTEM: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b''
INFO:MqttCon:SYSTEM: Sending CONNECT (u0, p0, wr0, wq0, wf0, c1, k60) client_id=b''
# more Sending CONNECT

最初版本的问题

最初使用常规connect方法的版本也存在相同问题:

if __name__ == "__main__":
    # setting mqtt client
    client.connect('<my_mqtt_url>', port=1883)
    client.loop_forever()
    client.disconnect()

补充信息

  • 重启客户端容器可恢复,但数小时后仍会出现同样的断开重连失败问题;
  • 故障发生前未挂起/恢复虚拟机,客户端与 broker 均运行在虚拟机上;
  • broker日志中看不到客户端重连尝试,但在客户端断开时能看到连接中断记录;
  • 未使用Wireshark抓包;
  • 客户端日志中存在代码16断开后成功重连的情况,但部分场景下无法重连。

临时解决方案

修改on_disconnect回调,当rc=16时退出程序:

def on_disconnect(client, userdata, rc):
    mqtt_logger.info("Device disconnected with result code: " + str(rc))
    if rc == 16:
        exit(1)

同时给容器设置restart: always,断开后重启容器恢复,但重启期间会丢失broker数据。

需求

寻求该问题的根本解决办法。


内容的提问来源于stack exchange,提问作者Motixa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 17:17:40