遗嘱机制
遗嘱机制
MQTT 协议中,死亡指的是“客户端掉线”、“与服务端断开了连接”这种意思。
掉线的两种方式:
客户端主动向服务端发送 DISCONNECT 报文,请求断开连接,自然服务端也就知道了客户端要离线了;
客户端意外掉线。被动与服务端断开了连接。
MQTT 从诞生之初就是专为低带宽、高延迟或不可靠网络等环境而设计的;所以针对这种意外掉线的情况,MQTT 协议使用了遗嘱机制来服务客户端、管理客户端。
MQTT 协议允许客户端在“活着”的时候就写好遗嘱,这样一旦客户端意外断线,服务端就可以将客户端的遗嘱公之于众。正常主动掉线的话就不会有这种情况
设置遗嘱

遗嘱消息和MQTT消息很相似,都有主题和正文内容
只有订阅了主题“clientWill”的客户端,才会收到这台客户端的遗嘱消息
遗嘱消息定义了遗嘱的内容。在本示例中,那些订阅了主题“clientWill”的客户端会在客户端意外断线时,收到服务端发布的“client offline”这样的信息。
willRetain -- 遗嘱消息的保留标志
遗嘱消息也可以设置为保留标志,用于告诉服务端是否需要对遗嘱消息进行保留处理。
/**
- @file demo.c
- @author 正点原子团队(ALIENTEK)
- @version V1.0
- @date 2022-06-21
- @brief ATK-MW8266D模块TCP透传实验
- @license Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
- @attention
- 实验平台:正点原子 阿波罗 F429开发板
- 在线视频:www.yuanzige.com
- 技术论坛:www.openedv.com
- 公司网址:www.alientek.com
- 购买地址:openedv.taobao.com
*/
#include "demo.h"
#include "./BSP/ATK_MW8266D/atk_mw8266d.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/KEY/key.h"
#include "./BSP/LCD/lcd.h"
#define DEMO_WIFI_SSID "ari"
#define DEMO_WIFI_PWD "zhanglanxiong"
#define DEMO_TCP_SERVER_IP "192.168.48.133"
#define DEMO_TCP_SERVER_PORT "1883"
/**
- @brief 显示IP地址
- @param 无
- @retval 无
*/
static void demo_show_ip(char *buf)
{
printf("IP: %s\r\n", buf);
lcd_show_string(60, 151, 128, 16, 16, buf, BLUE);
}
/**
@brief 按键0功能,功能测试
@param is_unvarnished: 0,未进入透传
1,已进入透传@retval 无
*/
static void demo_key0_fun(uint8_t is_unvarnished)
{
uint8_t ret;if (is_unvarnished == 0)
{
/* 进行AT指令测试 */ret = atk_mw8266d_at_test(); if (ret == 0) { printf("AT test success!\r\n"); } else { printf("AT test failed!\r\n"); }}
else
{
/* 通过透传,发送信息至TCP Server */
atk_mw8266d_uart_printf("This ATK-MW8266D TCP Connect Test.\r\n");
}
}
/**
@brief 按键1功能,切换透传模式
@param is_unvarnished: 0,未进入透传
1,已进入透传@retval 无
*/
static void demo_key1_fun(uint8_t *is_unvarnished)
{
uint8_t ret;if (is_unvarnished == 0)
{
/ 进入透传 */
ret = atk_mw8266d_enter_unvarnished();
if (ret == 0)
{
is_unvarnished = 1;
printf("Enter unvarnished!\r\n");
}
else
{
printf("Enter unvarnished failed!\r\n");
}
}
else
{
/ 退出透传 */
atk_mw8266d_exit_unvarnished();
*is_unvarnished = 0;
printf("Exit unvarnished!\r\n");
}
}
/**
@brief 进入透传时,将接收自TCP Server的数据发送到串口调试助手
@param is_unvarnished: 0,未进入透传
1,已进入透传@retval 无
*/
static void demo_upload_data(uint8_t is_unvarnished)
{
uint8_t *buf;if (is_unvarnished == 1)
{
/* 接收来自ATK-MW8266D UART的一帧数据 /
buf = atk_mw8266d_uart_rx_get_frame();
if (buf != NULL)
{
printf("%s", buf);
/ 重开开始接收来自ATK-MW8266D UART的数据 */
atk_mw8266d_uart_rx_restart();
}
}
}
// /**
// * @brief 例程演示入口函数
// * @param 无
// * @retval 无
// */
// void demo_run(void)
// {
// uint8_t ret;
// char ip_buf[16];
// uint8_t key;
// uint8_t is_unvarnished = 0;
// /* 初始化ATK-MW8266D */
// ret = atk_mw8266d_init(115200);
// if (ret != 0)
// {
// printf("ATK-MW8266D init failed!\r\n");
// while (1)
// {
// LED0_TOGGLE();
// delay_ms(200);
// }
// }
// printf("Joining to AP...\r\n");
// ret = atk_mw8266d_restore(); /* 恢复出厂设置 /
// ret += atk_mw8266d_at_test(); / AT测试 /
// ret += atk_mw8266d_set_mode(1); / Station模式 /
// ret += atk_mw8266d_sw_reset(); / 软件复位 /
// ret += atk_mw8266d_ate_config(0); / 关闭回显功能 /
// ret += atk_mw8266d_join_ap(DEMO_WIFI_SSID, DEMO_WIFI_PWD); / 连接WIFI /
// ret += atk_mw8266d_get_ip(ip_buf); / 获取IP地址 */
// if (ret != 0)
// {
// printf("Error to join ap!\r\n");
// while (1)
// {
// LED0_TOGGLE();
// delay_ms(200);
// }
// }
// demo_show_ip(ip_buf);
// /* 连接TCP服务器 */
// ret = atk_mw8266d_connect_tcp_server(DEMO_TCP_SERVER_IP, DEMO_TCP_SERVER_PORT);
// if (ret != 0)
// {
// printf("Error to connect tcp server!\r\n");
// while (1)
// {
// LED0_TOGGLE();
// delay_ms(200);
// }
// }
// /* 重新开始接收新的一帧数据 */
// atk_mw8266d_uart_rx_restart();
// while (1)
// {
// key = key_scan(0);
// switch (key)
// {
// case KEY0_PRES:
// {
// /* 功能测试 /
// demo_key0_fun(is_unvarnished);
// break;
// }
// case KEY1_PRES:
// {
// / 透传模式切换 */
// demo_key1_fun(&is_unvarnished);
// break;
// }
// default:
// {
// break;
// }
// }
// /* 发送透传接收自TCP Server的数据到串口调试助手 */
// demo_upload_data(is_unvarnished);
// delay_ms(10);
// }
// }
//原子云
void demo_run(void)
{
uint8_t ret;
char ip_buf[16];
uint8_t key;
uint8_t is_atkcld = 0;
/* 初始化ATK-MW8266D */
ret = atk_mw8266d_init(115200);
if (ret != 0)
{
printf("ATK-MW8266D init failed!\r\n");
while (1)
{
LED0_TOGGLE();
delay_ms(200);
}
}
printf("Joining to AP...\r\n");
ret = atk_mw8266d_restore(); /* 恢复出厂设置 */
ret += atk_mw8266d_at_test(); /* AT测试 */
ret += atk_mw8266d_set_mode(1); /* Station模式 */
ret += atk_mw8266d_sw_reset(); /* 软件复位 */
ret += atk_mw8266d_ate_config(0); /* 关闭回显功能 */
ret += atk_mw8266d_join_ap(DEMO_WIFI_SSID, DEMO_WIFI_PWD); /* 连接WIFI */
ret += atk_mw8266d_get_ip(ip_buf); /* 获取IP地址 */
if (ret != 0)
{
printf("Error to join ap!\r\n");
while (1)
{
LED0_TOGGLE();
delay_ms(200);
}
}
demo_show_ip(ip_buf);
/* 重新开始接收新的一帧数据 */
atk_mw8266d_uart_rx_restart();
while (1)
{
key = key_scan(0);
switch (key)
{
case KEY0_PRES:
{
/* 功能测试 */
demo_key0_fun(is_atkcld);
break;
}
case KEY1_PRES:
{
/* 切换原子云连接状态 */
demo_key1_fun(&is_atkcld);
break;
}
default:
{
break;
}
}
/* 发送接收自原子云的数据到串口调试助手 */
demo_upload_data(is_atkcld);
delay_ms(10);
}
}

