嵌入式|Linux下MQTT编译安装
目前,比较主流的两大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_C=ON-DPAHO_BUILD_EXAMPLES=ON-DCMAKE_PREFIX_PATH=/home/kevin/Code/mqtt_cpp_libs/sudocmake--buildbuild/--targetinstall如果已经安装mqtt c库,则可以忽略选项PAHO_WITH_MQTT_C,DCMAKE_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 *******************************************************************************/#include<stdio.h>#include<stdlib.h>#include<string.h>#include"MQTTAsync.h"#if!defined(_WIN32)#include<unistd.h>#else#include<windows.h>#endif#ifdefined(_WRS_KERNEL)#include<OsWrapper.h>#endif#defineADDRESS"tcp://127.0.0.1:1883"#defineCLIENTID"ExampleClientPub"#defineTOPIC"MQTT Examples"#definePAYLOAD"Hello World!"#defineQOS1#defineTIMEOUT10000Lintfinished=0;voidconnlost(void*context,char*cause){MQTTAsync client=(MQTTAsync)context;MQTTAsync_connectOptions conn_opts=MQTTAsync_connectOptions_initializer;intrc;printf("\nConnection lost\n");if(cause)printf(" cause: %s\n",cause);printf("Reconnecting\n");conn_opts.keepAliveInterval=20;conn_opts.cleansession=1;if((rc=MQTTAsync_connect(client,&conn_opts))!=MQTTASYNC_SUCCESS){printf("Failed to start connect, return code %d\n",rc);finished=1;}}voidonDisconnectFailure(void*context,MQTTAsync_failureData*response){printf("Disconnect failed\n");finished=1;}voidonDisconnect(void*context,MQTTAsync_successData*response){printf("Successful disconnection\n");finished=1;}voidonSendFailure(void*context,MQTTAsync_failureData*response){MQTTAsync client=(MQTTAsync)context;MQTTAsync_disconnectOptions opts=MQTTAsync_disconnectOptions_initializer;intrc;printf("Message send failed token %d error code %d\n",response->token,response->code);opts.onSuccess=onDisconnect;opts.onFailure=onDisconnectFailure;opts.context=client;if((rc=MQTTAsync_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 opts=MQTTAsync_disconnectOptions_initializer;intrc;printf("Message with token value %d delivery confirmed\n",response->token);opts.onSuccess=onDisconnect;opts.onFailure=onDisconnectFailure;opts.context=client;if((rc=MQTTAsync_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);finished=1;}voidonConnect(void*context,MQTTAsync_successData*response){MQTTAsync client=(MQTTAsync)context;MQTTAsync_responseOptions opts=MQTTAsync_responseOptions_initializer;MQTTAsync_message pubmsg=MQTTAsync_message_initializer;intrc;printf("Successful connection\n");opts.onSuccess=onSend;opts.onFailure=onSendFailure;opts.context=client;pubmsg.payload=PAYLOAD;pubmsg.payloadlen=(int)strlen(PAYLOAD);pubmsg.qos=QOS;pubmsg.retained=0;if((rc=MQTTAsync_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_opts=MQTTAsync_connectOptions_initializer;intrc;constchar*uri=(argc>1)?argv[1]:ADDRESS;printf("Using server at %s\n",uri);if((rc=MQTTAsync_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((rc=MQTTAsync_setCallbacks(client,client,connlost,messageArrived,NULL))!=MQTTASYNC_SUCCESS){printf("Failed to set callback, return code %d\n",rc);exit(EXIT_FAILURE);}conn_opts.keepAliveInterval=20;conn_opts.cleansession=1;conn_opts.onSuccess=onConnect;conn_opts.onFailure=onConnectFailure;conn_opts.context=client;if((rc=MQTTAsync_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\n""on 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 *******************************************************************************/#include<stdio.h>#include<stdlib.h>#include<string.h>#include"MQTTAsync.h"#if!defined(_WIN32)#include<unistd.h>#else#include<windows.h>#endif#ifdefined(_WRS_KERNEL)#include<OsWrapper.h>#endif#defineADDRESS"tcp://127.0.0.1:1883"#defineCLIENTID"ExampleClientSub"#defineTOPIC"MQTT Examples"#definePAYLOAD"Hello World!"#defineQOS1#defineTIMEOUT10000Lintdisc_finished=0;intsubscribed=0;intfinished=0;voidonConnect(void*context,MQTTAsync_successData*response);voidonConnectFailure(void*context,MQTTAsync_failureData*response);voidconnlost(void*context,char*cause){MQTTAsync client=(MQTTAsync)context;MQTTAsync_connectOptions conn_opts=MQTTAsync_connectOptions_initializer;intrc;printf("\nConnection lost\n");if(cause)printf(" cause: %s\n",cause);printf("Reconnecting\n");conn_opts.keepAliveInterval=20;conn_opts.cleansession=1;conn_opts.onSuccess=onConnect;conn_opts.onFailure=onConnectFailure;if((rc=MQTTAsync_connect(client,&conn_opts))!=MQTTASYNC_SUCCESS){printf("Failed to start connect, return code %d\n",rc);finished=1;}}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_finished=1;}voidonDisconnect(void*context,MQTTAsync_successData*response){printf("Successful disconnection\n");disc_finished=1;}voidonSubscribe(void*context,MQTTAsync_successData*response){printf("Subscribe succeeded\n");subscribed=1;}voidonSubscribeFailure(void*context,MQTTAsync_failureData*response){printf("Subscribe failed, rc %d\n",response->code);finished=1;}voidonConnectFailure(void*context,MQTTAsync_failureData*response){printf("Connect failed, rc %d\n",response->code);finished=1;}voidonConnect(void*context,MQTTAsync_successData*response){MQTTAsync client=(MQTTAsync)context;MQTTAsync_responseOptions opts=MQTTAsync_responseOptions_initializer;intrc;printf("Successful connection\n");printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n""Press Q<Enter> to quit\n\n",TOPIC,CLIENTID,QOS);opts.onSuccess=onSubscribe;opts.onFailure=onSubscribeFailure;opts.context=client;if((rc=MQTTAsync_subscribe(client,TOPIC,QOS,&opts))!=MQTTASYNC_SUCCESS){printf("Failed to start subscribe, return code %d\n",rc);finished=1;}}intmain(intargc,char*argv[]){MQTTAsync client;MQTTAsync_connectOptions conn_opts=MQTTAsync_connectOptions_initializer;MQTTAsync_disconnectOptions disc_opts=MQTTAsync_disconnectOptions_initializer;intrc;intch;constchar*uri=(argc>1)?argv[1]:ADDRESS;printf("Using server at %s\n",uri);if((rc=MQTTAsync_create(&client,uri,CLIENTID,MQTTCLIENT_PERSISTENCE_NONE,NULL))!=MQTTASYNC_SUCCESS){printf("Failed to create client, return code %d\n",rc);rc=EXIT_FAILURE;gotoexit;}if((rc=MQTTAsync_setCallbacks(client,client,connlost,msgarrvd,NULL))!=MQTTASYNC_SUCCESS){printf("Failed to set callbacks, return code %d\n",rc);rc=EXIT_FAILURE;gotodestroy_exit;}conn_opts.keepAliveInterval=20;conn_opts.cleansession=1;conn_opts.onSuccess=onConnect;conn_opts.onFailure=onConnectFailure;conn_opts.context=client;if((rc=MQTTAsync_connect(client,&conn_opts))!=MQTTASYNC_SUCCESS){printf("Failed to start connect, return code %d\n",rc);rc=EXIT_FAILURE;gotodestroy_exit;}while(!subscribed&&!finished)#ifdefined(_WIN32)Sleep(100);#elseusleep(10000L);#endifif(finished)gotoexit;do{ch=getchar();}while(ch!='Q'&&ch!='q');disc_opts.onSuccess=onDisconnect;disc_opts.onFailure=onDisconnectFailure;if((rc=MQTTAsync_disconnect(client,&disc_opts))!=MQTTASYNC_SUCCESS){printf("Failed to start disconnect, return code %d\n",rc);rc=EXIT_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
说明你的板子的编译器不支持C++17,可以通过降低mqtt版本,或者升高开发板gcc/g++版本解决。
总结
本文介绍了 Paho MQTT C++ 库的完整编译流程,包括依赖安装、Paho C 库与 C++ 库的编译与安装步骤,并针对常见的编译错误提供了解决方法。通过以上过程,可在支持的系统环境中顺利构建 Paho MQTT C++ 开发库。