MQTT遗愿(last will) paho.mqtt实现
一、 MQTT遗嘱
MQTT 可以设置遗嘱,客户端在连接Broker的时候将遗嘱内容(也是topic + payload形式,遗嘱也有一个主题)发送给Broker并保存在Broker中,当客户端因为非正常原因断开与Broker的连接时,Broker会将遗嘱信息发送给订阅了该主题(订阅遗嘱的主题)的客户端。
客户端正常调用DISCONNECT断开连接时属于正常断开连接,Broker不会发送遗嘱,而且会将遗嘱从Broker中删除。
遗嘱消息发布的条件,包括但不限于:
- 服务端检测到了一个I/O错误或者网络故障。
- 客户端在爆出连接(Keep Alive)的时间内未能通讯。
- 客户端没有发送DISCONNECT保温直接关闭了网络连接。
- 由于协议错误服务端关闭了网络连接。
一旦被发布或者服务端收到了客户端发送的DISCONNECT报文,遗嘱消息就必须从存储的会
话状态中移除。
二、基于paho.mqtt.c实现遗嘱功能
网上关于遗嘱的介绍不少,但是实际的例子却很少,按理说 paho.mqtt.c 这个库用的挺多的,但是也没找到相关的例子,自己写了一个,其实也挺简单的,代码如下:
// mqtt-last-will.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <MQTTClient.h>
#define ADDRESS "tcp://127.0.0.1:1883" // broker 地址
#define CLIENTID "mqtt_test_client" // client id
#define TOPIC "MQTT Examples" // 正常发布测试的主题
#define PAYLOAD "Hello World!" //正常发布时的payload
#define QOS 1
#define TIMEOUT 10000L
// last will topic and payload
#define LAST_WILL_TOPIC "Iamdie" // 遗嘱主题
#define LAST_WILL_MSG "I am really die." //遗嘱的内容
int main()
{
MQTTClient client;
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
//MQTTClient_SSLOptions ssl_opts = MQTTClient_SSLOptions_initializer; //不使用ssl加密
MQTTClient_willOptions will_opts = MQTTClient_willOptions_initializer;
int nRet = MQTTCLIENT_SUCCESS;
nRet = MQTTClient_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL);
if(nRet != MQTTCLIENT_SUCCESS)
{
printf("Failed to create client, return code %d\n", nRet);
return -1;
}
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;
//conn_opts.ssl = &ssl_opts; // ssl config //不使用ssl加密
// last will config 遗嘱设置
//will_opts.retained = 1; //retained = 1 时, broker会一直保留消息,这里不需要,使用默认的0就行
will_opts.topicName = LAST_WILL_TOPIC;
will_opts.message = LAST_WILL_MSG;
conn_opts.will = &will_opts;
// 连接broker
nRet = MQTTClient_connect(client, &conn_opts);
if (nRet != MQTTCLIENT_SUCCESS)
{
printf("Failed connect to broker, return code %d\n", nRet);
return -1;
}
// 测试发布消息
MQTTClient_message PubMsg = MQTTClient_message_initializer;
MQTTClient_deliveryToken token;
PubMsg.payload = (void*)PAYLOAD;
PubMsg.payloadlen = (int)strlen(PAYLOAD);
PubMsg.qos = QOS;
PubMsg.retained = 0;
if ((nRet = MQTTClient_publishMessage(client, TOPIC, &PubMsg, &token)) != MQTTCLIENT_SUCCESS)
{
printf("Failed to publish message, return code %d\n", nRet);
return -1;
}
nRet = MQTTClient_waitForCompletion(client, token, TIMEOUT);
// 这里正常执行 MQTTClient_disconnect 时是不发送遗嘱的,需要测试发送遗嘱的时候将disconnect 屏蔽掉,直接destroy就可以
if ((nRet = MQTTClient_disconnect(client, 10000)) != MQTTCLIENT_SUCCESS)
{
printf("Failed to disconnect, return code %d\n", nRet);
}
MQTTClient_destroy(&client);
return 0;
}