一、 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;
}