
目前比较主流的两大MQTT库是Paho库和Mosquitto库。Paho库支持几乎所有主流编程语言如C、C、Python、Java、JavaScript、Go等因此它非常适合需要跨平台或多语言支持的应用。Paho库由Eclipse基金会维护提供了完整的API广泛应用于物联网、移动设备和云服务中。今天记录一下Paho-mqtt的编译过程。1 Mosquitto配置1.1 安装Mosquitto本教程依赖Mosquitto做转发服务器来做订阅、发布操作流程图大概是这样# Ubuntu安装mosquitto服务sudoapt-getinstallmosquitto# centos安装命令sudoyuminstall-ymosquitto# 查看mosquitto服务状态systemctl status mosquitto下载完成自动启动用命令查看一下如图所示1.2 Mosquitto设置密码使用以下命令设置密码mosquitto_passwd-c/etc/mosquitto/passwd.conf user然后将密码放入配置文件# centosvim/etc/mosquitto/mosquitto.conf将allow_anonymous修改成false然后加上密码的路径如下图所示1.3 负载均衡配置vim/etc/mosquitto/mosquitto.conf# 在里面加上connection vm1-to-vm2 address10.10.20.211:9947 remote_clientid vm1-bridge remote_username 你要链接的mosquitto账号 remote_password 你要链接的mosquitto密码 try_privatetruecleansessionfalsestart_type automatic restart_timeout560notificationsfalsebridge_protocol_version mqttv311 bridge_outgoing_retaintruetopic color/# both 1注意 这里的10.10.20.211:9947只是实例 公网地址还是局域网地址取决于你两个服务器之间的关系然后重启生效systemctl restart mosquitto1.3 配置Mosquitto端口依旧是在/etc/mosquitto/mosquitto.conf文件中# centosvim/etc/mosquitto/mosquitto.conf2 Paho依赖安装官网地址在mqtt如官网所示构建过程需要以下工具sudoapt-getinstallbuild-essential gccmakecmakesudoapt-getinstalllibssl-devsudoapt-getinstalldoxygen graphviz3 构建Paho CPP 库gitclone https://github.com/eclipse/paho.mqtt.cppcdpaho.mqtt.cppgitcheckout v1.4.2gitsubmodule initgitsubmodule update cmake-Bbuild-H.-DPAHO_WITH_MQTT_CON-DPAHO_BUILD_EXAMPLESON-DCMAKE_PREFIX_PATH/home/kevin/Code/mqtt_cpp_libs/sudocmake--buildbuild/--targetinstall如果已经安装mqtt c库则可以忽略选项PAHO_WITH_MQTT_CDCMAKE_PREFIX_PATH表示你编译的库要安装的目录如果默认安装到系统路径也可以忽略。如图所示安装完成是这样的share/doc/Eclipse Paho C/samples/目录下有其示例代码:如果没有就是PAHO_BUILD_EXAMPLES选项没打开。4 代码测试4.1 CMakeLists加载cmake_minimum_required(VERSION 3.10) project(mqtt) set(CMAKE_CXX_STANDARD 11) set(PahoMqttCpp_DIR /home/kevin/Code/mqtt_cpp_libs/lib/cmake/PahoMqttCpp/) find_package(PahoMqttCpp REQUIRED) if(PahoMqttCpp_FOUND) message(STATUS Found Paho MQTT C library) else() message(FATAL_ERROR Paho MQTT C not found!) endif() # 包含你自己的头文件目录 include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) # 自动收集源文件 aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src SRC_FILES) # 创建可执行文件 add_executable(mqtt MQTTAsync_publish.c ${SRC_FILES}) # 链接到 Paho MQTT C 库使用目标名 target_link_libraries(mqtt PahoMqttCpp::paho-mqttpp3-shared)这里的PahoMqttCpp_DIR可以改成你自己安装的mqtt路径。4.2 publish代码/******************************************************************************* * Copyright (c) 2012, 2023 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * and Eclipse Distribution License v1.0 which accompany this distribution. * * The Eclipse Public License is available at * https://www.eclipse.org/legal/epl-2.0/ * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Ian Craggs - initial contribution *******************************************************************************/#includestdio.h#includestdlib.h#includestring.h#includeMQTTAsync.h#if!defined(_WIN32)#includeunistd.h#else#includewindows.h#endif#ifdefined(_WRS_KERNEL)#includeOsWrapper.h#endif#defineADDRESStcp://127.0.0.1:1883#defineCLIENTIDExampleClientPub#defineTOPICMQTT Examples#definePAYLOADHello World!#defineQOS1#defineTIMEOUT10000Lintfinished0;voidconnlost(void*context,char*cause){MQTTAsync client(MQTTAsync)context;MQTTAsync_connectOptions conn_optsMQTTAsync_connectOptions_initializer;intrc;printf(\nConnection lost\n);if(cause)printf( cause: %s\n,cause);printf(Reconnecting\n);conn_opts.keepAliveInterval20;conn_opts.cleansession1;if((rcMQTTAsync_connect(client,conn_opts))!MQTTASYNC_SUCCESS){printf(Failed to start connect, return code %d\n,rc);finished1;}}voidonDisconnectFailure(void*context,MQTTAsync_failureData*response){printf(Disconnect failed\n);finished1;}voidonDisconnect(void*context,MQTTAsync_successData*response){printf(Successful disconnection\n);finished1;}voidonSendFailure(void*context,MQTTAsync_failureData*response){MQTTAsync client(MQTTAsync)context;MQTTAsync_disconnectOptions optsMQTTAsync_disconnectOptions_initializer;intrc;printf(Message send failed token %d error code %d\n,response-token,response-code);opts.onSuccessonDisconnect;opts.onFailureonDisconnectFailure;opts.contextclient;if((rcMQTTAsync_disconnect(client,opts))!MQTTASYNC_SUCCESS){printf(Failed to start disconnect, return code %d\n,rc);exit(EXIT_FAILURE);}}voidonSend(void*context,MQTTAsync_successData*response){MQTTAsync client(MQTTAsync)context;MQTTAsync_disconnectOptions optsMQTTAsync_disconnectOptions_initializer;intrc;printf(Message with token value %d delivery confirmed\n,response-token);opts.onSuccessonDisconnect;opts.onFailureonDisconnectFailure;opts.contextclient;if((rcMQTTAsync_disconnect(client,opts))!MQTTASYNC_SUCCESS){printf(Failed to start disconnect, return code %d\n,rc);exit(EXIT_FAILURE);}}voidonConnectFailure(void*context,MQTTAsync_failureData*response){printf(Connect failed, rc %d\n,response?response-code:0);finished1;}voidonConnect(void*context,MQTTAsync_successData*response){MQTTAsync client(MQTTAsync)context;MQTTAsync_responseOptions optsMQTTAsync_responseOptions_initializer;MQTTAsync_message pubmsgMQTTAsync_message_initializer;intrc;printf(Successful connection\n);opts.onSuccessonSend;opts.onFailureonSendFailure;opts.contextclient;pubmsg.payloadPAYLOAD;pubmsg.payloadlen(int)strlen(PAYLOAD);pubmsg.qosQOS;pubmsg.retained0;if((rcMQTTAsync_sendMessage(client,TOPIC,pubmsg,opts))!MQTTASYNC_SUCCESS){printf(Failed to start sendMessage, return code %d\n,rc);exit(EXIT_FAILURE);}}intmessageArrived(void*context,char*topicName,inttopicLen,MQTTAsync_message*m){/* not expecting any messages */return1;}intmain(intargc,char*argv[]){MQTTAsync client;MQTTAsync_connectOptions conn_optsMQTTAsync_connectOptions_initializer;intrc;constchar*uri(argc1)?argv[1]:ADDRESS;printf(Using server at %s\n,uri);if((rcMQTTAsync_create(client,uri,CLIENTID,MQTTCLIENT_PERSISTENCE_NONE,NULL))!MQTTASYNC_SUCCESS){printf(Failed to create client object, return code %d\n,rc);exit(EXIT_FAILURE);}if((rcMQTTAsync_setCallbacks(client,client,connlost,messageArrived,NULL))!MQTTASYNC_SUCCESS){printf(Failed to set callback, return code %d\n,rc);exit(EXIT_FAILURE);}conn_opts.keepAliveInterval20;conn_opts.cleansession1;conn_opts.onSuccessonConnect;conn_opts.onFailureonConnectFailure;conn_opts.contextclient;if((rcMQTTAsync_connect(client,conn_opts))!MQTTASYNC_SUCCESS){printf(Failed to start connect, return code %d\n,rc);exit(EXIT_FAILURE);}printf(Waiting for publication of %s\non topic %s for client with ClientID: %s\n,PAYLOAD,TOPIC,CLIENTID);while(!finished)#ifdefined(_WIN32)Sleep(100);#elseusleep(10000L);#endifMQTTAsync_destroy(client);returnrc;}4.3 Subscribe代码/******************************************************************************* * Copyright (c) 2012, 2022 IBM Corp., Ian Craggs * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * and Eclipse Distribution License v1.0 which accompany this distribution. * * The Eclipse Public License is available at * https://www.eclipse.org/legal/epl-2.0/ * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Ian Craggs - initial contribution *******************************************************************************/#includestdio.h#includestdlib.h#includestring.h#includeMQTTAsync.h#if!defined(_WIN32)#includeunistd.h#else#includewindows.h#endif#ifdefined(_WRS_KERNEL)#includeOsWrapper.h#endif#defineADDRESStcp://127.0.0.1:1883#defineCLIENTIDExampleClientSub#defineTOPICMQTT Examples#definePAYLOADHello World!#defineQOS1#defineTIMEOUT10000Lintdisc_finished0;intsubscribed0;intfinished0;voidonConnect(void*context,MQTTAsync_successData*response);voidonConnectFailure(void*context,MQTTAsync_failureData*response);voidconnlost(void*context,char*cause){MQTTAsync client(MQTTAsync)context;MQTTAsync_connectOptions conn_optsMQTTAsync_connectOptions_initializer;intrc;printf(\nConnection lost\n);if(cause)printf( cause: %s\n,cause);printf(Reconnecting\n);conn_opts.keepAliveInterval20;conn_opts.cleansession1;conn_opts.onSuccessonConnect;conn_opts.onFailureonConnectFailure;if((rcMQTTAsync_connect(client,conn_opts))!MQTTASYNC_SUCCESS){printf(Failed to start connect, return code %d\n,rc);finished1;}}intmsgarrvd(void*context,char*topicName,inttopicLen,MQTTAsync_message*message){printf(Message arrived\n);printf( topic: %s\n,topicName);printf( message: %.*s\n,message-payloadlen,(char*)message-payload);MQTTAsync_freeMessage(message);MQTTAsync_free(topicName);return1;}voidonDisconnectFailure(void*context,MQTTAsync_failureData*response){printf(Disconnect failed, rc %d\n,response-code);disc_finished1;}voidonDisconnect(void*context,MQTTAsync_successData*response){printf(Successful disconnection\n);disc_finished1;}voidonSubscribe(void*context,MQTTAsync_successData*response){printf(Subscribe succeeded\n);subscribed1;}voidonSubscribeFailure(void*context,MQTTAsync_failureData*response){printf(Subscribe failed, rc %d\n,response-code);finished1;}voidonConnectFailure(void*context,MQTTAsync_failureData*response){printf(Connect failed, rc %d\n,response-code);finished1;}voidonConnect(void*context,MQTTAsync_successData*response){MQTTAsync client(MQTTAsync)context;MQTTAsync_responseOptions optsMQTTAsync_responseOptions_initializer;intrc;printf(Successful connection\n);printf(Subscribing to topic %s\nfor client %s using QoS%d\n\nPress QEnter to quit\n\n,TOPIC,CLIENTID,QOS);opts.onSuccessonSubscribe;opts.onFailureonSubscribeFailure;opts.contextclient;if((rcMQTTAsync_subscribe(client,TOPIC,QOS,opts))!MQTTASYNC_SUCCESS){printf(Failed to start subscribe, return code %d\n,rc);finished1;}}intmain(intargc,char*argv[]){MQTTAsync client;MQTTAsync_connectOptions conn_optsMQTTAsync_connectOptions_initializer;MQTTAsync_disconnectOptions disc_optsMQTTAsync_disconnectOptions_initializer;intrc;intch;constchar*uri(argc1)?argv[1]:ADDRESS;printf(Using server at %s\n,uri);if((rcMQTTAsync_create(client,uri,CLIENTID,MQTTCLIENT_PERSISTENCE_NONE,NULL))!MQTTASYNC_SUCCESS){printf(Failed to create client, return code %d\n,rc);rcEXIT_FAILURE;gotoexit;}if((rcMQTTAsync_setCallbacks(client,client,connlost,msgarrvd,NULL))!MQTTASYNC_SUCCESS){printf(Failed to set callbacks, return code %d\n,rc);rcEXIT_FAILURE;gotodestroy_exit;}conn_opts.keepAliveInterval20;conn_opts.cleansession1;conn_opts.onSuccessonConnect;conn_opts.onFailureonConnectFailure;conn_opts.contextclient;if((rcMQTTAsync_connect(client,conn_opts))!MQTTASYNC_SUCCESS){printf(Failed to start connect, return code %d\n,rc);rcEXIT_FAILURE;gotodestroy_exit;}while(!subscribed!finished)#ifdefined(_WIN32)Sleep(100);#elseusleep(10000L);#endifif(finished)gotoexit;do{chgetchar();}while(ch!Qch!q);disc_opts.onSuccessonDisconnect;disc_opts.onFailureonDisconnectFailure;if((rcMQTTAsync_disconnect(client,disc_opts))!MQTTASYNC_SUCCESS){printf(Failed to start disconnect, return code %d\n,rc);rcEXIT_FAILURE;gotodestroy_exit;}while(!disc_finished){#ifdefined(_WIN32)Sleep(100);#elseusleep(10000L);#endif}destroy_exit:MQTTAsync_destroy(client);exit:returnrc;}4.4 测试如图所示先打开订阅端代码然后运行发布端代码订阅端收到消息5 报错undefined reference to std::filesystem说明你的板子的编译器不支持C17可以通过降低mqtt版本或者升高开发板gcc/g版本解决。总结本文介绍了 Paho MQTT C 库的完整编译流程包括依赖安装、Paho C 库与 C 库的编译与安装步骤并针对常见的编译错误提供了解决方法。通过以上过程可在支持的系统环境中顺利构建 Paho MQTT C 开发库。