Mosquitto 2.0.18 MQTTv5初始连接失败后无法自动重连及内存泄漏问题
问题解决方案
一、解决首次连接失败不自动重连的问题
Mosquitto的自动重连机制依赖客户端处于合理的配置状态,你的初始化流程顺序有误,导致内置重连逻辑未生效:
- 调整初始化顺序:先完成所有客户端配置(协议版本、用户名密码、回调、重连参数),再启动loop线程,最后发起连接请求。
- 移除手动循环连接逻辑:依赖Mosquitto内置的自动重连机制,无需手动重复调用
mosquitto_connect_async。
修正后的初始化代码示例:
char sn[64] = {0}; mqtt_prop_sn_get(NULL, sn, sizeof(sn)); g_mosq = mosquitto_new(sn, session, NULL); if (!g_mosq) { MOCAR_LOG_ERROR("create client fail"); return -1; } // 1. 设置MQTTv5协议版本 mosquitto_int_option(g_mosq, MOSQ_OPT_PROTOCOL_VERSION, MQTT_PROTOCOL_V5); // 2. 配置用户名密码 mosquitto_username_pw_set(g_mosq, g_mqtt_info.user_id, g_mqtt_info.password); // 3. 绑定V5版本回调函数 mosquitto_connect_v5_callback_set(g_mosq, my_connect_v5_callback); mosquitto_message_v5_callback_set(g_mosq, my_message_v5_callback); mosquitto_subscribe_v5_callback_set(g_mosq, my_subscribe_v5_callback); mosquitto_disconnect_v5_callback_set(g_mosq, my_disconnect_v5_callback); // 4. 开启自动重连:初始延迟5秒,最大延迟15秒,启用指数退避 mosquitto_reconnect_delay_set(g_mosq, 5, 15, true); // 5. 启动loop处理线程 int loop = mosquitto_loop_start(g_mosq); if (loop != MOSQ_ERR_SUCCESS) { MOCAR_LOG_ERROR_FMT("mosquitto loop error"); huali_plf_mqtt_cleanup(); return -1; } // 6. 发起异步连接,后续连接失败由loop线程自动触发重连 int ret = mosquitto_connect_async(g_mosq, mqtt_info.address, mqtt_info.port, KEEP_ALIVE); if (MOSQ_ERR_SUCCESS != ret) { if (MOSQ_ERR_INVAL == ret) { MOCAR_LOG_DEBUG_FMT("the input parameters were invalid"); huali_plf_mqtt_cleanup(); return -1; } else { MOCAR_LOG_DEBUG_FMT("initial mqtt connect failed, auto-reconnect will start: %s", mosquitto_strerror(ret)); } }
关键说明:
- Mosquitto的自动重连逻辑在
mosquitto_loop_start创建的线程中运行,只要配置了mosquitto_reconnect_delay_set,无论首次连接失败还是后续连接断开,都会按设定策略自动重连。 - 手动循环调用
mosquitto_connect_async会与内置重连机制冲突,应当移除。
二、解决手动重连时的内存泄漏问题
当前手动重连流程频繁启停loop线程是内存泄漏的核心原因——mosquitto_loop_start会创建新线程,频繁操作可能导致线程资源未完全释放。正确做法是保持loop线程持续运行,仅重新发起连接请求:
修正后的重连代码示例:
void mqtt_check_reconnect(void) { if (1 != cv2x_plf_mqtt_get_send_flag()) { // 检查当前连接状态,仅在断开时发起重连 if (mosquitto_connection_status(g_mosq) != MOSQ_CONN_CONNECTED) { int rc = mosquitto_reconnect_async(g_mosq); if (rc != MOSQ_ERR_SUCCESS) { MOCAR_LOG_ERROR_FMT("mqtt reconnect failed: %s", mosquitto_strerror(rc)); } else { MOCAR_LOG_DEBUG_FMT("mqtt reconnect initiated"); } } } }
若需重置参数后重连,也无需重启loop线程,调整为如下流程:
void mqtt_check_reconnect(void) { if (1 != cv2x_plf_mqtt_get_send_flag()) { int rc = 0; // 断开当前连接(无需停止loop线程) mosquitto_disconnect(g_mosq); // 重置用户名密码(按需执行) mosquitto_username_pw_set(g_mosq, g_mqtt_info.user_id, g_mqtt_info.password); // 重新发起异步连接 rc = mosquitto_connect_async(g_mosq, mqtt_info.address, mqtt_info.port, KEEP_ALIVE); if (rc != MOSQ_ERR_SUCCESS) { MOCAR_LOG_ERROR_FMT("mqtt reconnect failed: %s", mosquitto_strerror(rc)); } } }
关键说明:
mosquitto_loop_start仅需在初始化时调用一次,后续连接状态变化由该线程自动处理,无需频繁启停。- 使用
mosquitto_reconnect_async或mosquitto_connect_async发起重连,复用已有loop线程,避免线程资源泄漏。 - 若问题仍存在,可尝试升级至Mosquitto 2.0.x系列最新稳定版,部分旧版本存在线程资源释放的已知bug。
内容的提问来源于stack exchange,提问作者buerwang
相关产品推荐
相关产品推荐

