如何使用libuv poll接收mosquitto MQTT消息及读取不全问题排查
代码错误点及修复方案
核心错误点
- 调用
mosquitto_loop_read后再自行调用recv读取socket:mosquitto_loop_read已经把socket上的待读数据全部读到了mosquitto库内部的缓冲区做协议解析,你后续调用recv只能拿到库没读完的剩余数据,自然内容不全。 - 错误使用mosquitto库的设计逻辑:mosquitto库已经封装了完整的MQTT帧解析、粘包处理逻辑,不需要用户直接读取原始socket数据。你注释掉了
mosquitto_message_callback_set配置,没有通过官方提供的消息回调获取完整解析后的MQTT payload,反而直接读取原始socket,属于API使用错误。 - poll handler中错误使用
gets函数打印日志:gets是用于从标准输入读取内容的函数,参数应为可写的字符数组,传入字符串常量会触发内存访问错误,需要改为printf。 - 未处理可写事件:你在
uv_poll_start中同时监听了UV_READABLE和UV_WRITABLE事件,但在poll handler中完全没有实现可写事件对应的mosquitto_loop_write调用,会导致MQTT心跳、消息发送等逻辑异常。 - main函数中socket合法性判断错误:代码中写的是
if (mosqInfo.mosqSocket == 0),但mosquitto_socket返回-1才代表获取失败,0是标准输入的文件描述符,这个错误会导致socket获取失败的场景无法被正确捕获。
修复步骤
- 实现自定义的消息回调函数,示例如下:
void messageCallback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg) { // msg->payload就是完整的MQTT消息内容,msg->payloadlen是内容长度 printf("完整接收消息:%.*s\n", (int)msg->payloadlen, (char*)msg->payload); }
- 恢复
mqttInit函数中注释掉的回调配置代码:
mosquitto_message_callback_set(mosqInfo->mosq, messageCallback);
- 删除
mqttPollHandler中所有自行调用recv的代码,修正gets错误,补充可写事件的处理逻辑,修改后的poll handler示例:
static void mqttPollHandler(uv_poll_t* poll, int status, int events) { mosquittoInfo* mosqInfo = NULL; if (status < 0) { printf("error handling mqtt socket\n"); return; } mosqInfo = (mosquittoInfo*)poll->data; mosquitto_loop_misc(mosqInfo->mosq); if (events & UV_READABLE) { mosquitto_loop_read(mosqInfo->mosq, 1); } if (events & UV_WRITABLE) { mosquitto_loop_write(mosqInfo->mosq, 1); } // 根据mosquitto内部状态动态更新监听的事件 int need_write = mosquitto_want_write(mosqInfo->mosq); int new_events = UV_READABLE | (need_write ? UV_WRITABLE : 0); uv_poll_start(poll, new_events, mqttPollHandler); }
- 修正main函数中的socket判断逻辑:
if (mosqInfo.mosqSocket == -1) { printf("error getting mosquitto socket\n"); return 0; }
内容的提问来源于stack exchange,提问作者lalalalz
相关产品推荐
相关产品推荐

