零基础入门学用物联网(ESP8266) 第二部分 MQTT基础篇(四)

参考教程:https://www.bilibili.com/video/BV1L7411c7jw/?spm_id_from=333.1387.favlist.content.click

十、保留消息

1、保留消息的概念及作用

(1)MQTT服务端收到指定为保留消息的MQTT报文后,会将其保存,只要有MQTT客户端订阅该主题,MQTT服务端马上将该主题信息发给它;MQTT服务端收到指定为非保留消息的MQTT报文后,则不会将其保存。

(2)当MQTT服务端收到同一主题的保留消息时,后者将会覆盖前者,当有MQTT客户端订阅该主题时,MQTT服务端会将该主题最新收到的保留消息发给MQTT客户端。

2、发布保留消息的方法

MQTT设备发布的保留消息的流程与发布普通消息的流程十分类似,唯一区别是,在发布保留消息时,MQTT设备需要将PUBLISH报文中retainFlag设置为true;如果要发布非保留消息,那么PUBLISH报文中retainFlag设置为false

3、修改保留消息的方法

每一个主题只能有一个"保留消息",如果MQTT客户端想要更新"保留消息",就需要向该主题发送一条新的"保留消息",这样MQTT服务端会将新的"保留消息"覆盖旧的"保留消息",当有MQTT客户端订阅该主题时,MQTT服务端就会将最新的"保留消息"发送给订阅的MQTT客户端了

4、删除保留消息的方法

如果要删除一个主题的"保留消息",可以向该主题发布一条空的"保留消息",也就是发送一条0字节payload的"保留消息"

5、ESP8266保留消息应用

(1)先前介绍了publish函数的其中一种形式,在调用PubSubClient类的publish函数发布消息时,函数参数依次为要发布的主题和消息内容,不过publish函数还有第二种形式,该形式下需要传入的函数参数不仅有要发布的主题和消息内容,还有retainFlag配置参数,置为True则指定该消息为保留消息,置为False则指定该消息为非保留消息。

(2)使用ESP8266发布MQTT保留消息示例代码:

cpp 复制代码
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
 
// 设置Wi-Fi接入信息
const char* ssid = "Zevalin_Computer";
const char* password = "00114514";
const char* mqttServer = "test.mosquitto.org";   //如无法使用,可更换为其它公用MQTT服务端地址
 
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
 
int count;    // Ticker计数用变量
 
void setup() {
  Serial.begin(9600);
  WiFi.mode(WIFI_STA);  //设置ESP8266工作模式为无线终端模式
  connectWifi();        //连接Wi-Fi
  
  mqttClient.setServer(mqttServer, 1883);  //设置MQTT服务端和端口号
  connectMQTTServer();  //连接MQTT服务端
 
  if (mqttClient.connected()) { // 如果开发板成功连接服务器
    pubRetMQTTmsg();            // 发布信息   
}
 
void loop() { 
    // 保持心跳
    mqttClient.loop();
}

void connectMQTTServer(){
  // 根据ESP8266的MAC地址生成客户端ID(避免与其它ESP8266的客户端ID重名)
  String clientId = "esp8266-" + WiFi.macAddress();
 
  // 连接MQTT服务端
  if (mqttClient.connect(clientId.c_str())) { 
    Serial.println("MQTT Server Connected.");
    Serial.println("Server Address: ");
    Serial.println(mqttServer);
    Serial.println("ClientId:");
    Serial.println(clientId);
  }
  else {
    Serial.print("MQTT Server Connect Failed. Client State:");
    Serial.println(mqttClient.state());
    delay(3000);
  }   
}
 
void pubRetMQTTmsg(){  // 发布信息
  // 建立发布主题
  String topicString = "Taichi-Maker-Ret-" + WiFi.macAddress();
  char publishTopic[topicString.length() + 1];  
  strcpy(publishTopic, topicString.c_str());
 
  // 建立即将发布的保留消息,消息内容为"Retained Msg"
  String messageString = "Retained Msg"; 
  char publishMsg[messageString.length() + 1];   
  strcpy(publishMsg, messageString.c_str());
  
  // 实现ESP8266向主题发布retained信息
  // 以下publish函数第三个参数用于设置保留信息(retained message)
  if(mqttClient.publish(publishTopic, publishMsg, true)){
    Serial.println("Publish Topic:");Serial.println(publishTopic);
    Serial.println("Publish Retained message:");Serial.println(publishMsg);    
  }
  else {
    Serial.println("Message Publish Failed."); 
  }
}
 
void connectWifi(){   // ESP8266连接Wi-Fi
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000); Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi Connected!");  
  Serial.println(""); 
}

(3)使用ESP8266删除MQTT保留消息示例代码,与使用ESP8266发布MQTT保留消息示例代码类似,修改pubRetMQTTmsg的函数实现即可。

cpp 复制代码
void pubRetMQTTmsg(){  // 发布信息
  // 建立发布主题
  String topicString = "Taichi-Maker-Ret-" + WiFi.macAddress();
  char publishTopic[topicString.length() + 1];  
  strcpy(publishTopic, topicString.c_str());
 
  // 如果要删除主题的"保留消息",可以通过向该主题发布一条空的"保留消息"
  String messageString = ""; 
  char publishMsg[messageString.length() + 1];   
  strcpy(publishMsg, messageString.c_str());
  
  // 实现ESP8266向主题发布retained信息
  // 以下publish函数第三个参数用于设置保留信息(retained message)
  if(mqttClient.publish(publishTopic, publishMsg, true)){
    Serial.println("Publish Topic:");Serial.println(publishTopic);
    Serial.println("Publish Retained message:");Serial.println(publishMsg);    
  }
  else {
    Serial.println("Message Publish Failed."); 
  }
}

十一、心跳机制

1、心跳机制的概念及作用

(1)心跳机制就是MQTT客户端在没有向MQTT服务端发送信息时,定时地向MQTT服务端发送一条消息,这条用于心跳机制的消息也被称作心跳请求(PINGREQ),心跳请求的作用正是用于告知MQTT服务端,当前MQTT客户端依然在线,MQTT服务端在收到MQTT客户端的心跳请求后,会回复一条消息,这条回复消息被称作心跳响应(PINGRESP)。

(2)由于心跳请求是MQTT客户端定时发送的,一旦MQTT服务端发现MQTT客户端停止发送请求信息,那么MQTT服务端就会知道,这台MQTT客户端已经断开了连接。

(3)这个心跳机制不仅可以用于MQTT服务端判断MQTT客户端是否保持连接,也可以用于MQTT客户端判断自己与MQTT服务端是否保持连接,如果MQTT客户端在发送心跳请求(PINGREQ)后,没有收到MQTT服务端的心跳响应(PINGRESP),那么MQTT客户端就会认为自己与MQTT服务端的连接已经被断开了。

2、心跳时间间隔的设置

(1)MQTT客户端连接服务端时会向MQTT服务端发送CONNECT报文,而CONNECT报文可以包含参数KeepAlive------心跳时间间隔,单位为s。

(2)如果CONNECT报文中将此参数明确,那么MQTT客户端和MQTT服务端都明确了心跳时间间隔,MQTT客户端知道多久要发送一条心跳请求给MQTT服务端,MQTT服务端知道多久没收到MQTT客户端的心跳请求算是连接断开。

3、心跳机制的运作

(1)如果MQTT客户端在心跳时间间隔内发布了消息给MQTT服务端,那么MQTT服务端不需要MQTT客户端发送心跳请求,也可以确定该MQTT客户端在线。

(2)如果MQTT客户端在心跳时间间隔内没有发布消息给MQTT服务端,那么MQTT客户端将主动发送一个心跳请求消息给MQTT服务端,以表面自己仍然在线。

(3)简而言之,MQTT客户端在心跳间隔时间内,如果有消息发布,那就直接发布消息而不发布心跳请求,但是在心跳间隔时间内,MQTT客户端没有消息发布,那么它就会发布一条心跳请求给MQTT服务端。

(4)在实际运行中,如果MQTT服务端没有在1.5倍心跳时间间隔内收到MQTT客户端发布的消息(PUBLISH)或心跳请求(PINGREQ),那么MQTT服务端就会认为这个MQTT客户端已经掉线。举例来说,如果心跳时间间隔是60秒,那么MQTT服务端在90秒内没有收到MQTT客户端发布的消息,也没有收到MQTT客户端的PINGREQ请求,那么它就会认为MQTT客户端已经掉线。

(5)心跳机制不仅仅用于MQTT服务端判断MQTT客户端是否在线,MQTT客户端也可以利用这一机制来判断自己是否与MQTT服务端仍保持连接,如果MQTT客户端发送了心跳请求(PINGREQ)给MQTT服务端一段时间后,没有收到MQTT服务端回复的心跳确认,那么MQTT客户端也会认为自己已经断开了与MQTT服务端的连接。

相关推荐
贺小涛2 小时前
STM32学习
stm32·单片机·学习
凉、介2 小时前
SylixOS 多核启动
服务器·笔记·学习·嵌入式·sylixos
银月光科技2 小时前
细分市场带动下 UV LED行业发展潜力巨大
人工智能·物联网·uv
DA02212 小时前
系统移植-STM32MP1_TF-A概述
单片机·系统移植·stm32mp1
2301_822782824 小时前
C语言利用EasyX实现图形化界面的小游戏
c语言·单片机·图形化界面·lcd菜单·接口实现
kyle~4 小时前
ROS2---客户端服务(rclcpp::Client)
c++·物联网·机器人·ros2
Heartache boy4 小时前
野火STM32_HAL库版课程笔记-TIM触发ADC采集
笔记·stm32·单片机·嵌入式硬件
你疯了抱抱我4 小时前
【Altium Designer】网络线(颜色、旋转、粗细);网络标签 && 端口的差别(重点!)
嵌入式硬件·嵌入式·pcb·电路
Alaso_shuang4 小时前
一些通信协议科普
网络·嵌入式·通信