使用libmosquitto库连接MQTT broker时如何检测用户名密码错误
问题原因
mosquitto_connect() 的返回值仅代表TCP层连接发起/建立的操作结果,无法反映MQTT协议层的连接状态。用户名密码鉴权属于MQTT协议层逻辑,需要服务端返回CONNACK控制报文后才能确认结果,你当前代码在TCP连接建立后直接判定成功,自然捕获不到鉴权失败的错误。
实现方案
你需要通过注册连接回调的方式获取MQTT层的连接结果,同时启动libmosquitto的事件循环处理服务端返回的报文,修改后的代码如下:
/* compile using: $ gcc -o libmosq libmosq.c -lmosquitto */ #include <stdio.h> #include <mosquitto.h> #include <stdlib.h> #include <unistd.h> // 自定义连接回调函数 void on_connect(struct mosquitto *mosq, void *obj, int rc) { if(rc == MOSQ_ERR_SUCCESS) { printf("connection success\n"); } else if(rc == MOSQ_ERR_CONN_REFUSED_NOT_AUTHORIZED) { fprintf(stderr, "Connection Refused: not authorised\n"); // 鉴权失败可以直接退出或者做重连逻辑 exit(1); } else { fprintf(stderr, "connection failed, return code: %d\n", rc); exit(1); } } int main(int argc, char *argv[]) { struct mosquitto *mosq = NULL; mosquitto_lib_init(); mosq = mosquitto_new(NULL, true, NULL); if(!mosq) { fprintf(stderr, "Error: Out of memory.\n"); exit(1); } mosquitto_username_pw_set(mosq, "user1", "passwd1"); // 注册连接回调 mosquitto_connect_callback_set(mosq, on_connect); int resultCode = mosquitto_connect(mosq, "localhost", 1883, 60); if (resultCode != MOSQ_ERR_SUCCESS) { // 这里仅捕获TCP层错误,比如服务端端口未监听、网络不可达等 fprintf(stderr, "TCP connection error: %s\n", mosquitto_strerror(resultCode)); exit(1); } // 启动事件循环,处理所有MQTT报文和回调 mosquitto_loop_forever(mosq, -1, 1); // 资源清理(实际运行不会走到这,可在信号处理函数中调用) mosquitto_destroy(mosq); mosquitto_lib_cleanup(); return 0; }
关键修改说明
- 新增
on_connect回调函数:第三个参数rc为MQTT连接返回码,其中MOSQ_ERR_CONN_REFUSED_NOT_AUTHORIZED(值为5)就是鉴权失败的返回码,其他返回码可以参考libmosquitto的头文件定义判断对应错误类型 - 调用
mosquitto_connect_callback_set()将自定义回调注册到mosquitto实例中 - 用
mosquitto_loop_forever()替换原来的sleep调用:libmosquitto需要事件循环处理网络报文、触发对应的回调函数,没有事件循环的话服务端返回的CONNACK报文不会被处理,回调也不会触发
如果你需要同步等待连接结果再执行后续逻辑,可以自行定义全局/静态标志位,在on_connect回调中修改标志位,主线程循环等待标志位变更后再执行后续操作即可。
mosquitto_sub工具可以正常返回鉴权错误的原因就是它内部已经实现了上述的回调注册和事件循环逻辑,会等CONNACK报文返回后再输出对应结果。
内容的提问来源于stack exchange,提问作者fgalan
相关产品推荐
相关产品推荐

