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;
}
posted @ 2020-07-13 22:46  ay-a  阅读(2601)  评论(0编辑  收藏  举报