1.下载PAHO MQTT包
wget https://codeload.github.com/eclipse/paho.mqtt.c/tar.gz/refs/tags/v1.3.13
2.解压PAHO MQTT压缩包
tar -zxvf paho.mqtt.c-1.3.13.tar.gz
3.创建生成文件位置
mkdir build
4.cd build
5.配置交叉编译
cmake -DPAHO_WITH_SSL=TRUE -DOPENSSL_ROOT_DIR=/home/seuls/Documents/libs/openssl-1.1.1w/build -DCMAKE_INSTALL_PREFIX=$PWD/install -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc …
说明:
1.DPAHO_WITH_SSL:是否开启SSL加密,开启为TRUE,不开启为FALSE
2.DOPENSSL_ROOT_DIR:SSL校验的相关路径
3.X-DCMAKE_INSTALL_PREFIX:是指定paho最终的安装路径用的
4.DCMAKE_C_COMPILER:交叉编译工具链的名称
注:如果不需要SSL校验,将DPAHO_WITH_SSL设为FALSE,DCMAKE_INSTALL_PREFIX不设置
6.make编译
7.make install安装
8.安装成功后生成4个文件夹
1.include中生成的是头文件
2.lib是生成的动态库
9.实现PAHO MQTT异步订阅和发布
1.需要将交叉编译生成的include和lib拷贝到项目当中
注:主要需要的是头文件MQTTAsync.h和静态库lib paho-mqtt3a.so和libpaho-mqtt3c.so
2.代码说明
设置登录MQTT端的账号、密码
`#include "MQTTAsync.h"
#define ADD_TIME_MS 0 //8*3600*1000
char g_sn[64] = "xxxxxx";//客户端标识符
char g_account[] = "xxxx";//用户名
char g_pwd[] = "xxxxx";//密码
char g_clientId[64];
char s_ServerIp[] = "xxx.xxx.xxx.xxx";//mqtt服务器地址
static const char* OPT_SEND = "MQTTAsync_sendMessage";
static const char* OPT_SUB = "MQTTAsync_subscribe";
static const char* OPT_UNSUB = "MQTTAsync_unsubscribe";
static MQTTAsync s_Client = NULL;//通过 MQTTAsync_create() 创建的 MQTT 客户端实例
static int s_cloudStatus = DEVICE_OFFLINE;
extern pthread_mutex_t g_db_mutex;
volatile DEObjectSt g_detectionStatus;
MQTTInfoSt g_mqttObj;
创建mqtt客户端
int MQTTAsync ps_MQTT_Connect(void)
{
int rc = 0;
char temp_address[128] = {0}; //服务器地址
FILE *fp;
char topicBuf[256] = {0};
char *message = NULL;
MQTTAsync_createOptions opts = MQTTAsync_createOptions_initializer;//用于设置创建选项,比如连接超时时间、是否自动重连等
MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;//设置连接的选项结构体初始化
MQTTAsync_willOptions will_opts = MQTTAsync_willOptions_initializer;//遗嘱消息结构体初始化
MQTTAsync_setTraceCallback(mqttTraceCallback);
opts.MQTTVersion = MQTTVERSION_5;//要使用的 MQTT 版本
sprintf(topicBuf, "/xxx/%s/xxx");//topic内容
strncpy(g_mqttObj.ip,s_ServerIp,sizeof(s_ServerIp));
g_mqttObj.port = xxxx;//端口号
sprintf(temp_address,"tcp://%s:%d",g_mqttObj.ip, g_mqttObj.port);
//创建mqtt客户端
if ((rc = MQTTAsync_createWithOptions(&s_Client, temp_address, g_sn, MQTTCLIENT_PERSISTENCE_NONE, NULL,&opts)) != MQTTASYNC_SUCCESS)
{
return NULL;
}
/*Set the mqtt callback*/
mqtt_set_callbacks();
cJSON* willPayload = cJSON_CreateObject();
if (willPayload){
conn_opts.keepAliveInterval = 30;//心跳包发送间隔时间
conn_opts.connectTimeout = CONNECT_TIMEOUT;
conn_opts.automaticReconnect = AUTO_CONN;//开启断开自动重连
conn_opts.minRetryInterval = 1;//最小重连间隔时间(秒),每次失败重连间隔时间都会加倍
conn_opts.maxRetryInterval = 32;//最大重连间隔时间(秒)
//conn_opts.username = USRNAME;
//conn_opts.password = PASSWORD;
conn_opts.username = g_account;
conn_opts.password = g_pwd;
conn_opts.cleansession = 0;//连接标识,为 1 时表示启用“干净会话”
conn_opts.onSuccess = onConnect;/*连接成功回调,此处设置的回调只在第一次连接成功时调用,SDK内部自动重连时不会调用;*/
conn_opts.onFailure = onConnectFailure;//连接失败回调
conn_opts.context = s_Client;
will_opts.retained = 0; //retained = 1 时, broker会一直保留消息,这里不需要,使用默认的0就行
will_opts.topicName = topicBuf;
message = ps_will_message_create(willPayload);
if (message){
will_opts.message = message;
}
conn_opts.will = &will_opts;
建立与 MQTT 代理(服务器)连接 一个异步的 MQTT 客户端实现
if ((rc = MQTTAsync_connect(s_Client, &conn_opts)) != MQTTASYNC_SUCCESS)
{
/* rc的返回值为正确,大于为错误代码
1:连接被拒绝 - 不可接受的协议版本。
2:连接被拒绝 - 标识符被拒绝。
3:连接被拒绝 - 服务器不可用。
4:连接被拒绝 - 用户名或密码错误。
5:连接被拒绝 - 未经授权
*/
if (message){
cJSON_free(message);
}
if(willPayload)
{
cJSON_Delete(willPayload);
}
return NULL;
}
if (message){
cJSON_free(message);
}
if(willPayload)
{
cJSON_Delete(willPayload);
}
}
return s_Client;
}
订阅主题
int ps_MQTT_SubTopic(char *topicName)
{
MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
int rc;
opts.onSuccess = onOptSuccess;
opts.onFailure = onOptFail;
opts.context = (void*)OPT_SUB;
if(s_cloudStatus == DEVICE_OFFLINE){
return -1;
}
if ((rc = MQTTAsync_subscribe(s_Client,topicName, QOS, &opts)) != MQTTASYNC_SUCCESS)
{
return -1;
}
return 0;
}
**向主题发布消息**
int ps_MQTT_SendMsg(char *topicName,const char *payload)
{
MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
int rc = 0;
opts.onSuccess = onOptSuccess;
opts.onFailure = onOptFail;
opts.context = (void*)OPT_SEND;
pubmsg.payload = (void*)payload;
pubmsg.payloadlen = strlen(payload);
pubmsg.qos = QOS;
pubmsg.retained = 0;
if(s_cloudStatus == DEVICE_OFFLINE){
return -1;
}
//向MQTT服务器发送消息
if(s_Client){
if ((rc = MQTTAsync_sendMessage(s_Client, topicName, &pubmsg, &opts)) != MQTTASYNC_SUCCESS)
{
return -1;
}
}
return rc;
}
解释:topicName:要发布消息的目标主题名称
payload:发布的内容
取消订阅
int ps_MQTT_UnsubTopic(const char *topicName)
{
debug_log(LOGT_INFO, "to unsubtopic:%s \n",topicName);
MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
int rc;
opts.onSuccess = onOptSuccess;
opts.onFailure = onOptFail;
opts.context = (void*)OPT_UNSUB;
if(s_cloudStatus == DEVICE_OFFLINE){
return -1;
}
//取消订阅 MQTT 主题
if ((rc = MQTTAsync_unsubscribe(s_Client,topicName,&opts)) != MQTTASYNC_SUCCESS)
{
return -1;
}
return rc;
}
回调函数
static void mqtt_set_callbacks(void)
{
MQTTAsync_setConnectionLostCallback(s_Client,NULL,connlost);// MQTT 客户端与 MQTT 服务器的连接丢失时调用的回调函数
MQTTAsync_setMessageArrivedCallback(s_Client,NULL,messageArrived);//设置当 MQTT 客户端接收到新消息时调用的回调函数
MQTTAsync_setDeliveryCompleteCallback(s_Client,NULL,onDeliveryComplete);//用于设置当 MQTT 客户端发送的消息被成功接收到时调用的回调函数
MQTTAsync_setConnected(s_Client,NULL,onConnectBuild);//用于设置当 MQTT 客户端成功连接到 MQTT 服务器时调用的回调函数
//此函数尝试断开客户端与MQTT的连接服务器。以便让客户端有时间完成消息处理当调用此函数时,超时时间为指定。当超时时间超过时,客户端甚至断开连接如果仍有未完成的邮件确认
MQTTAsync_setDisconnected(s_Client,NULL,onDisConnected);//用于设置当 MQTT 客户端与 MQTT 服务器断开连接时调用的回调函数
//MQTTAsync_setCallbacks
}
接收订阅主题消息函数
int messageArrived(void* context, char* topicName, int topicLen, MQTTAsync_message* message)
{
MQTTAsync_freeMessage(&message);
MQTTAsync_free(topicName);
return 1;
}
解释:message为接收到的消息
获取运行状态
int ps_get_cloud_status(void)
{
return s_cloudStatus;
}
连接丢失
static void connlost(void *context, char *cause)
{
if(context == NULL || cause == NULL)
{
s_cloudStatus = DEVICE_OFFLINE;
return;
}
char topicBuf[256] = {0};
char *message = NULL;
MQTTAsync client = (MQTTAsync)context;
MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
MQTTAsync_willOptions will_opts = MQTTAsync_willOptions_initializer;
int rc;
char ccuid[32] = {0};
char pid[32] = {0};
sprintf(topicBuf, "/inspection/%s/heartbeat", g_sn);
debug_log(LOGT_INFO, "\nConnection lost\n");
debug_log(LOGT_INFO, "cause: %s\n", cause);
s_cloudStatus = DEVICE_OFFLINE;
cJSON* willPayload = cJSON_CreateObject();
if (willPayload){
message = ps_will_message_create(willPayload);
if (message){
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 0;
will_opts.retained = 0; //retained = 1 时, broker会一直保留消息,这里不需要,使用默认的0就行
will_opts.topicName = topicBuf;
will_opts.message = message;
conn_opts.will = &will_opts;
if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS)
{
debug_log(LOGT_ERR, "Failed to start connect, return code %d\n", rc);
}
cJSON_free(message);
}
message = NULL;
cJSON_Delete(willPayload);
}
willPayload = NULL;
}
断开连接失败
void onDisconnectFailure(void* context, MQTTAsync_failureData* response)
{
}
断开连接
void onDisconnect(void* context, MQTTAsync_successData* response)
{
}
发送消息失败
void onSendFailure(void* context, MQTTAsync_failureData* response)
{
if(context == NULL || response == NULL)
{
return;
}
MQTTAsync client = (MQTTAsync)context;
MQTTAsync_disconnectOptions opts = MQTTAsync_disconnectOptions_initializer;
int rc;
opts.onSuccess = onDisconnect;
opts.onFailure = onDisconnectFailure;
opts.context = client;
//断开MQTT客户端与MQTT服务器连接
if ((rc = MQTTAsync_disconnect(client, &opts)) != MQTTASYNC_SUCCESS)
{
}
}
发送消息
void onSend(void* context, MQTTAsync_successData* response)
{
if(response == NULL)
{
return;
}
}
连接失败
void onConnectFailure(void* context, MQTTAsync_failureData* response)
{
if(response == NULL)
{
return;
}
}
补充
static void onOptSuccess(void* context, MQTTAsync_successData* response)
{
if(strcmp((char *)context,OPT_SEND)==0)
{
}
else if(strcmp((char *)context,OPT_SUB)==0)
{
}
else if(strcmp((char *)context,OPT_UNSUB)==0)
{
}
}
static void onOptFail(void* context, MQTTAsync_failureData* response)
{
if(strcmp((char *)context,OPT_SEND)==0)
{
}
else if(strcmp((char *)context,OPT_SUB)==0)
{
}
else if(strcmp((char *)context,OPT_UNSUB)==0)
{
}
}