注释和头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MQTTClient.h"
#define ADDRESS "tcp://localhost:1883"
#define CLIENTID "ExampleClientPub"
#define TOPIC "MQTT Examples"
#define PAYLOAD "Hello World!"
#define QOS 1
#define TIMEOUT 10000L
ADDRESS:MQTT代理服务器的地址
CLIENTID:MQTT客户端的唯一标识符
TOPIC:要接收消息的主题名称
PAYLOAD:要发布的消息内容
QOS:消息的服务质量等级。在这个例子中,服务质量等级是1,表示至少一次传递
TIMEOUT:操作的超时时间,以毫秒为单位。在这个例子中,超时时间是10000毫秒,即10秒
定义了结构体的变量
volatile MQTTClient_deliveryToken deliveredtoken;
子函数解析
/*
*@void *context:上下文信息,可以在回调函数中传递额外的数据或状态。在这个例子中,没有使用上下文信息,所以可以将其忽略。
*@MQTTClient_deliveryToken dt:消息的传递令牌。
*/
void delivered(void *context,MQTTClient_deliveryToken dt)
{
printf("Message with token %d delivery xonfirmed\n",dt);//首先打印出消息的传递令牌,以确认消息已经成功传递。
deliveredtoken = dt;//然后,将传递令牌保存在全局变量deliveredtoken中,以便在其他地方使用。
}
context:上下文信息,可以在回调函数中传递额外的数据或状态。在这个例子中,没有使用上下文信息,所以可以将其忽略
dt:消息的传递令牌
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
int i;
char* payloadptr;
printf("Message arrived\n");
printf(" topic: %s\n", topicName);
printf(" message: ");
payloadptr = message->payload;
for(i=0; i<message->payloadlen; i++)
{
putchar(*payloadptr++);
}
putchar('\n');
MQTTClient_freeMessage(&message);
MQTTClient_free(topicName);
return 1;
}
topicName:收到来自哪个主题的消息
topicLen:主题的长度
message:消息体:payload(消息体,字符串) payloadlen:消息的长度
通过定义回调函数并在其中处理接收到的消息,可以根据需要对消息进行处理,例如打印、存储或执行其他操作。
void connlost(void *context,char *cause)
{
printf("\nConnection lost\n");//当断开链接时,打印以下内容
printf(" cause: %s\n",cause);
}
context:指向上下文的指针,可以在函数中使用该指针来访问其他变量或数据
cause:表示连接丢失的原因的字符串
这个函数的目的是在MQTT连接丢失时提供一个通知,以便应用程序可以采取适当的措施,例如重新连接或记录错误信息
主函数解析
int main(int argc, char* argv[])
{
MQTTClient client;
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
int rc;
int ch;
MQTTClient Client; 定义客户端句柄
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; 赋值宏定义,可以设置连接选项的各种参数,例如用户名、密码、超时时间等
//创建客户端,并且指定客户端连接的MQTT服务器地址和客户端ID
MQTTClient_create(&Client,ADDRESS,CLIENTID,MQTTCLIENT_PERSISTENCE_NONE,NULL);
/*
*@&Client:指向MQTT客户端实例的指针,用于接收
*@ADDRESS:MQTT代理服务器的地址。
*@CLIENTID:客户端的唯一标识符。
*@MQTTCLIENT_PERSISTENCE_NONE:表示不使用持久化存储。
*@NULL:表示不使用上下文信息。
*/
Client:指向MQTT客户端实例的指针,用于接收
ADDRESS:MQTT代理服务器的地址
CLIENTID:客户端的唯一标识符
MQTTCLIENT_PERSISTENCE_NONE:表示不使用持久化存储
NULL:表示不使用上下文信息
//初始化链接函数
conn_opts.keepAliveInterval = 20;//心跳保持间隔为20秒,每隔20秒发一次消息
conn_opts.cleansession = 1;//清理会话标志设制为1,清除之前的会话信息
conn_opts.keepAliveInterval = 20; 心跳保持间隔为20秒,每隔20秒发一次消息
conn_opts.cleansession = 1; 清理会话标志设制为1,清除之前的会话信息
//设置回调接口,只需要关注msgarrvd:消息到达后,会自动调用这个接口
MQTTClient_setCallbacks(Client,NULL,connlost,msgarrvd,delivered);
/*
*@Client:MQTT客户端实例。
*@NULL:表示不使用上下文信息。
*@connlost:连接丢失回调函数,用于在连接断开时执行相应的操作。
*@msgarrvd:消息到达回调函数,用于在接收到订阅的消息时执行相应的操作。
*@delivered:消息传递完成回调函数,用于在消息成功传递到代理服务器时执行相应的操作。
*/
Client:MQTT客户端实例
NULL:表示不使用上下文信息
connlost:连接丢失回调函数,用于在连接断开时执行相应的操作
msgarrvd:消息到达回调函数,用于在接收到订阅的消息时执行相应的操作
delivered:消息传递完成回调函数,用于在消息成功传递到代理服务器时执行相应的操作
//链接到broker
if((rc = MQTTClient_connect(Client,&conn_opts)) != MQTTCLIENT_SUCCESS)
{
printf("Failed to connect, return code %d\n", rc);
exit(EXIT_FAILURE);
}
printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n"
"Press Q<Enter> to quit\n\n", TOPIC, CLIENTID, QOS);
//订阅某个主题,指定订阅主题的名字,可以指定qos服务质量
MQTTClient_subscribe(Client, TOPIC, QOS);
代码尝试使用MQTTClient_connect函数连接到broker,并将连接选项conn_opts作为参数传递。如果连接成功,则返回值rc将为MQTTCLIENT_SUCCESS,否则将打印连接失败的消息并退出程序,代码使用printf函数打印出订阅的主题、客户端ID和服务质量等信息,最后,使用MQTTClient_subscribe函数订阅指定的主题。它接受三个参数:Client表示MQTT客户端对象,TOPIC表示要订阅的主题名称,QOS表示订阅的服务质量等级,这段代码的目的是建立与MQTT broker的连接,并订阅一个特定的主题,以接收该主题的消息。
do
{
ch = getchar();
} while(ch!='Q' && ch != 'q');
待用户输入,直到用户输入字符'Q'或'q'为止
MQTTClient_unsubscribe(client, TOPIC);
MQTTClient_disconnect(client, 10000);
MQTTClient_destroy(&client);
return rc;
}
取消订阅、断开连接和销毁MQTT客户端实例
完整代码展示
/*******************************************************************************
* Copyright (c) 2012, 2017 IBM Corp.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* 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 "MQTTClient.h"
#define ADDRESS "tcp://localhost:1883"
#define CLIENTID "ExampleClientSub"
#define TOPIC "MQTT Examples"
#define PAYLOAD "Hello World!"
#define QOS 1
#define TIMEOUT 10000L
volatile MQTTClient_deliveryToken deliveredtoken;
void delivered(void *context, MQTTClient_deliveryToken dt)
{
printf("Message with token value %d delivery confirmed\n", dt);
deliveredtoken = dt;
}
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
int i;
char* payloadptr;
printf("Message arrived\n");
printf(" topic: %s\n", topicName);
printf(" message: ");
payloadptr = message->payload;
for(i=0; i<message->payloadlen; i++)
{
putchar(*payloadptr++);
}
putchar('\n');
MQTTClient_freeMessage(&message);
MQTTClient_free(topicName);
return 1;
}
void connlost(void *context, char *cause)
{
printf("\nConnection lost\n");
printf(" cause: %s\n", cause);
}
int main(int argc, char* argv[])
{
MQTTClient client;
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
int rc;
int ch;
MQTTClient_create(&client, ADDRESS, CLIENTID,
MQTTCLIENT_PERSISTENCE_NONE, NULL);
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered);
if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
{
printf("Failed to connect, return code %d\n", rc);
exit(EXIT_FAILURE);
}
printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n"
"Press Q<Enter> to quit\n\n", TOPIC, CLIENTID, QOS);
MQTTClient_subscribe(client, TOPIC, QOS);
do
{
ch = getchar();
} while(ch!='Q' && ch != 'q');
MQTTClient_unsubscribe(client, TOPIC);
MQTTClient_disconnect(client, 10000);
MQTTClient_destroy(&client);
return rc;
}
使用实例(订阅和发布)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MQTTClient.h"
#include "cJSON.h"
#define ADDRESS "tcp://192.168.158.129:1883" //MQTT代理服务器的地址
#define CLIENTID "yyyyyyyy" //MQTT客户端的唯一标识符
#define TOPIC "down" //要接收消息的主题名称
#define TOPIC2 "up" //要发布消息的主题名称
#define PAYLOAD "Hello World!" //要发布的消息内容。
#define QOS 1 //消息的服务质量等级。在这个例子中,服务质量等级是1,表示至少一次传递。
#define TIMEOUT 10000L //操作的超时时间,以毫秒为单位。在这个例子中,超时时间是10000毫秒,即10秒。
//定义了结构体的变量
volatile MQTTClient_deliveryToken deliveredtoken;
/*
*@void *context:上下文信息,可以在回调函数中传递额外的数据或状态。在这个例子中,没有使用上下文信息,所以可以将其忽略。
*@MQTTClient_deliveryToken dt:消息的传递令牌。
*/
void delivered(void *context,MQTTClient_deliveryToken dt)
{
printf("Message with token %d delivery xonfirmed\n",dt);//首先打印出消息的传递令牌,以确认消息已经成功传递。
deliveredtoken = dt;//然后,将传递令牌保存在全局变量deliveredtoken中,以便在其他地方使用。
}
/**
* @brief
*
* @param context
* @param topicName 收到来自哪个主题的消息
* @param topicLen 主题的长度
* @param message 消息体:payload(消息体,字符串) payloadlen:消息的长度
* @return int
*/
int msgarrvd(void *context,char *topicName,int topicLen,MQTTClient_message *message)
{
int i;
char *payloadptr;
cJSON *root = cJSON_Parse((char *)message->payload);
if(NULL == root)
{
printf("Message arrivd\n");//在回调函数中,首先打印出收到消息的主题名称和消息内容。
printf(" topic 传输的JSON格式有误\n");//printf函数用于打印字符串和变量的值。%s是格式化字符串的占位符,用于打印字符串类型的值。
printf(" message: ");
}
else
{
printf("Message arrivd\n");//在回调函数中,首先打印出收到消息的主题名称和消息内容。
printf(" topic %s\n",topicName);//printf函数用于打印字符串和变量的值。%s是格式化字符串的占位符,用于打印字符串类型的值。
printf(" message: ");
#if 0
payloadptr = message->payload;
for(i=0; i<message->payloadlen; i++)
{
putchar(*payloadptr++);
}
#endif
printf("recv msg = %s\n", (char *)message->payload);//(char *)message->payload是将消息内容转换为字符串类型。
MQTTClient_freeMessage(&message);//然后,使用MQTTClient_freeMessage函数释放接收到的消息的内存。
/*message是一个指向MQTTClient_message结构体的指针,用于指定要释放的消息。 */
MQTTClient_free(topicName);//接下来,使用MQTTClient_free函数释放接收到消息的主题名称的内存。
/*topicName是一个指向字符数组的指针,用于指定要释放的主题名称。 */
}
return 1;//最后,返回值为1,表示消息已经处理完毕。
}
/*通过定义回调函数并在其中处理接收到的消息,可以根据需要对消息进行处理,例如打印、存储或执行其他操作。 */
void connlost(void *context,char *cause)
{
printf("\nConnection lost\n");//当断开链接时,打印以下内容
printf(" cause: %s\n",cause);
}
int main(int argc, char const *argv[])
{
//客户端句柄
MQTTClient Client;//定义结构体变量
//链接参数
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;//赋值宏定义
/*可以设置连接选项的各种参数,例如用户名、密码、超时时间等。 */
MQTTClient_message pubmsg = MQTTClient_message_initializer;//将pubmsg的所有字段初始化为默认值。
MQTTClient_deliveryToken token;//接收消息的传递令牌
int rc;
int ch;
//创建客户端,并且指定客户端连接的MQTT服务器地址和客户端ID
MQTTClient_create(&Client,ADDRESS,CLIENTID,MQTTCLIENT_PERSISTENCE_NONE,NULL);
/*
*@&Client:指向MQTT客户端实例的指针,用于接收
*@ADDRESS:MQTT代理服务器的地址。
*@CLIENTID:客户端的唯一标识符。
*@MQTTCLIENT_PERSISTENCE_NONE:表示不使用持久化存储。
*@NULL:表示不使用上下文信息。
*/
//初始化链接函数
conn_opts.keepAliveInterval = 20;//心跳保持间隔为20秒,每隔20秒发一次消息
conn_opts.cleansession = 1;//清理会话标志设制为1,清除之前的会话信息
//设置回调接口,只需要关注msgarrvd:消息到达后,会自动调用这个接口
MQTTClient_setCallbacks(Client,NULL,connlost,msgarrvd,delivered);
/*
*@Client:MQTT客户端实例。
*@NULL:表示不使用上下文信息。
*@connlost:连接丢失回调函数,用于在连接断开时执行相应的操作。
*@msgarrvd:消息到达回调函数,用于在接收到订阅的消息时执行相应的操作。
*@delivered:消息传递完成回调函数,用于在消息成功传递到代理服务器时执行相应的操作。
*/
//链接到broker
if((rc = MQTTClient_connect(Client,&conn_opts)) != MQTTCLIENT_SUCCESS)
{
printf("Failed to connect, return code %d\n", rc);
exit(EXIT_FAILURE);
}
printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n"
"Press Q<Enter> to quit\n\n", TOPIC, CLIENTID, QOS);
//订阅某个主题,指定订阅主题的名字,可以指定qos服务质量
MQTTClient_subscribe(Client, TOPIC, QOS);
//死循环,直到收到了一个q就退出
char buf[1024]="";
char buf1[1024]="";
do
{
bzero(buf,sizeof(buf));//清空数组
bzero(buf1,sizeof(buf1));//清空数组
cJSON *root = cJSON_CreateObject();//创建一个树干
//创建名叫name的子树杈
cJSON *item = cJSON_CreateString("yyyyyyyy");
//把子树杈放到树干上
cJSON_AddItemToObject(root, "name", item);
//创建名叫age的子树杈
item = cJSON_CreateNumber(14);
//把子树杈放到树干上
cJSON_AddItemToObject(root, "age", item);
//创建名叫name的子树杈
fscanf(stdin,"%s",buf1);
item = cJSON_CreateString(buf1);
//把子树杈放到树干上
cJSON_AddItemToObject(root, "msg", item);
sprintf(buf,"%s",cJSON_PrintUnformatted(root));
pubmsg.payload = buf;//要发送的内容
pubmsg.payloadlen = sizeof(buf);//要发送的大小
pubmsg.qos = QOS; //服务质量等级是1,表示至少一次传递。
pubmsg.retained = 0; //要发布的消息是否保留。在这个例子中,保留标志是0,表示不保留消息。
MQTTClient_publishMessage(Client, TOPIC2, &pubmsg, &token);
printf("Waiting for up to %d seconds for publication of %s\n"
"on topic %s for client with ClientID: %s\n",
(int)(TIMEOUT/1000), PAYLOAD, TOPIC, CLIENTID);
rc = MQTTClient_waitForCompletion(Client, token, TIMEOUT);
/*
*@MQTTClient client:MQTT客户端实例。
*@MQTTClient_deliveryToken token:消息的传递令牌。
*@unsigned long timeout:等待的超时时间,以毫秒为单位。
*/
printf("Message with delivery token %d delivered\n", token);//成功发送后打印令牌
} while(buf[35]!='Q' && buf[36] !='\"');//当数组是大写Q并且第二位没有数时结束
//取消订阅、断开连接和销毁MQTT客户端实例
MQTTClient_unsubscribe(Client, TOPIC);
MQTTClient_unsubscribe(Client, TOPIC2);
MQTTClient_disconnect(Client, 10000);
MQTTClient_destroy(&Client);
return rc;
}
以上代码实现订阅和发送两种功能,用到cJSON.h,编译需要链接paho-mqtt3c