下面讲解 RT-Thread 提供的 MQTT 示例代码,测试服务器使用 Eclipse 的测试服务器,地址 iot.eclipse.org
,端口 1883
,MQTT 功能示例代码如下:
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <rtthread.h>
#define DBG_ENABLE
#define DBG_SECTION_NAME "[MQTT] "
#define DBG_LEVEL DBG_LOG
#define DBG_COLOR
#include <rtdbg.h>
#include "paho_mqtt.h"
#define MQTT_URI "tcp://iot.eclipse.org:1883" // 配置测试服务器地址
#define MQTT_USERNAME "admin"
#define MQTT_PASSWORD "admin"
#define MQTT_SUBTOPIC "/mqtt/test" // 设置订阅主题
#define MQTT_PUBTOPIC "/mqtt/test" // 设置推送主题
#define MQTT_WILLMSG "Goodbye!" // 设置遗言消息
/* 定义 MQTT 客户端环境结构体 */
static MQTTClient client;
/* MQTT 订阅事件自定义回调函数 */
static void mqtt_sub_callback(MQTTClient *c, MessageData *msg_data)
{
*((char *)msg_data->message->payload + msg_data->message->payloadlen) = '\0';
LOG_D("mqtt sub callback: %.*s %.*s",
msg_data->topicName->lenstring.len,
msg_data->topicName->lenstring.data,
msg_data->message->payloadlen,
(char *)msg_data->message->payload);
return;
}
/* MQTT 订阅事件默认回调函数 */
static void mqtt_sub_default_callback(MQTTClient *c, MessageData *msg_data)
{
*((char *)msg_data->message->payload + msg_data->message->payloadlen) = '\0';
LOG_D("mqtt sub default callback: %.*s %.*s",
msg_data->topicName->lenstring.len,
msg_data->topicName->lenstring.data,
msg_data->message->payloadlen,
(char *)msg_data->message->payload);
return;
}
/* MQTT 连接事件回调函数 */
static void mqtt_connect_callback(MQTTClient *c)
{
LOG_D("inter mqtt_connect_callback!");
}
/* MQTT 上线事件回调函数 */
static void mqtt_online_callback(MQTTClient *c)
{
LOG_D("inter mqtt_online_callback!");
}
/* MQTT 下线事件回调函数 */
static void mqtt_offline_callback(MQTTClient *c)
{
LOG_D("inter mqtt_offline_callback!");
}
/**
* 这个函数创建并配置 MQTT 客户端。
*
* @param void
*
* @return none
*/
static void mq_start(void)
{
/* 使用 MQTTPacket_connectData_initializer 初始化 condata 参数 */
MQTTPacket_connectData condata = MQTTPacket_connectData_initializer;
static char cid[20] = { 0 };
static int is_started = 0;
if (is_started)
{
return;
}
/* 配置 MQTT 结构体内容参数 */
{
client.uri = MQTT_URI;
/* 产生随机的客户端 ID */
rt_snprintf(cid, sizeof(cid), "rtthread%d", rt_tick_get());
/* 配置连接参数 */
memcpy(&client.condata, &condata, sizeof(condata));
client.condata.clientID.cstring = cid;
client.condata.keepAliveInterval = 60;
client.condata.cleansession = 1;
client.condata.username.cstring = MQTT_USERNAME;
client.condata.password.cstring = MQTT_PASSWORD;
/* 配置 MQTT 遗言参数 */
client.condata.willFlag = 1;
client.condata.will.qos = 1;
client.condata.will.retained = 0;
client.condata.will.topicName.cstring = MQTT_PUBTOPIC;
client.condata.will.message.cstring = MQTT_WILLMSG;
/* 分配缓冲区 */
client.buf_size = client.readbuf_size = 1024;
client.buf = malloc(client.buf_size);
client.readbuf = malloc(client.readbuf_size);
if (!(client.buf && client.readbuf))
{
LOG_E("no memory for MQTT client buffer!");
goto _exit;
}
/* 设置事件回调函数 */
client.connect_callback = mqtt_connect_callback;
client.online_callback = mqtt_online_callback;
client.offline_callback = mqtt_offline_callback;
/* 设置订阅表和事件回调函数*/
client.messageHandlers[0].topicFilter = MQTT_SUBTOPIC;
client.messageHandlers[0].callback = mqtt_sub_callback;
client.messageHandlers[0].qos = QOS1;
/* 设置默认的订阅主题*/
client.defaultMessageHandler = mqtt_sub_default_callback;
}
/* 运行 MQTT 客户端 */
paho_mqtt_start(&client);
is_started = 1;
_exit:
return;
}
/**
* 这个函数推送消息给特定的 MQTT 主题。
*
* @param send_str publish message
*
* @return none
*/
static void mq_publish(const char *send_str)
{
MQTTMessage message;
const char *msg_str = send_str;
const char *topic = MQTT_PUBTOPIC;
message.qos = QOS1; //消息等级
message.retained = 0;
message.payload = (void *)msg_str;
message.payloadlen = strlen(message.payload);
MQTTPublish(&client, topic, &message);
return;
}
#ifdef RT_USING_FINSH
#include <finsh.h>
FINSH_FUNCTION_EXPORT(mq_start, startup mqtt client);
FINSH_FUNCTION_EXPORT(mq_publish, publish mqtt msg);
#ifdef FINSH_USING_MSH
MSH_CMD_EXPORT(mq_start, startup mqtt client);
int mq_pub(int argc, char **argv)
{
if (argc != 2)
{
rt_kprintf("More than two input parameters err!!\n");
return 0;
}
mq_publish(argv[1]);
return 0;
}
MSH_CMD_EXPORT(mq_pub, publish mqtt msg);
#endif /* FINSH_USING_MSH */
#endif /* RT_USING_FINSH */
在 msh 中运行上述功能示例代码,可以实现向服务器订阅主题和向特定主题推送消息的功能, 功能示例代码运行效果如下:
- 启动 MQTT 客户端,连接代理服务器并订阅主题:
msh />mq_start /* 启动 MQTT 客户端连接 Eclipse 服务器 */
inter mqtt_connect_callback! /* 服务器连接成功,调用连接回调函数打印服务器信息 */
ipv4 address port: 1883
[MQTT] HOST = 'iot.eclipse.org'
msh />[MQTT] Subscribe #0 /mqtt/test OK! /* 订阅主题 /mqtt/test 成功 */
inter mqtt_online_callback! /* MQTT 上线成功,调用上线回调函数 */
msh />
- 作为发布者向指定主题发布消息:
msh />mq_pub hello-rtthread /* 向指定主题发送 hello-rtthread 消息 */
msh />mqtt sub callback: /mqtt/test hello-rtthread /* 收到消息,执行回调函数 */
msh />