3. QoS 0消息传递
任务目标
本案例要求你在ESP32上配置MQTT客户端,以QoS 0级别发布和订阅消息,并通过人为制造网络不稳定来观察QoS 0可能带来的消息丢失现象。完成本案例后,你将理解QoS 0的“尽力而为”特性及其适用场景。
环境与依赖
- 硬件:ESP32开发板(如ESP32-DevKitC)
- 软件:Arduino IDE(需安装ESP32开发板支持包)或ESP-IDF
- MQTT Broker:本地运行Mosquitto(或使用公共测试Broker如broker.emqx.io:1883)
- 所需库:PubSubClient(Arduino环境下通过库管理器安装)
完整实现代码
以下代码实现了QoS 0消息的发布与订阅。核心逻辑包括:连接WiFi、连接MQTT Broker、订阅主题、以QoS 0发布消息,并通过串口输出消息ID以便观察丢失情况。
#include <WiFi.h>
#include <PubSubClient.h>
// WiFi配置
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
// MQTT Broker配置
const char* mqtt_server = "broker.emqx.io";
const int mqtt_port = 1883;
const char* client_id = "ESP32_QoS0_Client";
// 主题定义
const char* pub_topic = "esp32/qos0/test";
const char* sub_topic = "esp32/qos0/response";
WiFiClient espClient;
PubSubClient client(espClient);
// 消息计数器
unsigned int msgCounter = 0;
unsigned long lastPublishTime = 0;
const unsigned long publishInterval = 2000; // 每2秒发布一次
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect(client_id)) {
Serial.println("connected");
client.subscribe(sub_topic, 0); // QoS 0订阅
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
// 定时发布QoS 0消息
if (millis() - lastPublishTime > publishInterval) {
lastPublishTime = millis();
msgCounter++;
String payload = "QoS0_MSG_" + String(msgCounter);
client.publish(pub_topic, payload.c_str(), false); // QoS 0发布
Serial.print("Published: ");
Serial.print(payload);
Serial.print(" | QoS: 0 | MsgID: ");
Serial.println(msgCounter);
}
}
运行与验证方法
运行步骤:
- 在Arduino IDE中,将上述代码中的WiFi凭据替换为你自己的网络信息。
- 选择正确的开发板(Tools → Board → ESP32 Dev Module)和端口,编译并上传代码。
- 打开串口监视器(波特率115200),观察ESP32连接WiFi和MQTT Broker的日志。
验证QoS 0消息传递:
- 在PC上安装Mosquitto客户端工具(或使用MQTT X等图形工具),订阅主题
esp32/qos0/test:
mosquitto_sub -h broker.emqx.io -t "esp32/qos0/test" -v
- 观察串口监视器,ESP32每2秒发布一条带递增编号的消息。PC端应能收到大部分消息,但可能偶尔丢失。
- 制造消息丢失:在ESP32运行期间,拔掉路由器电源5秒再恢复。重新连接后,观察串口输出——ESP32会继续从断点编号发布消息,但PC端收到的消息编号会出现跳号(例如从5直接跳到8),证明QoS 0在连接中断期间的消息已丢失。
通过判定标准:
- PC端收到的消息编号不连续(存在跳号),证明QoS 0不保证消息必达。
- ESP32串口输出显示消息编号连续递增,说明发送端未感知丢失。
- 重新连接后,ESP32能自动恢复发布(无需重启),且PC端能继续收到新消息。
关键说明
QoS 0是MQTT协议中开销最低的级别,消息发送后即丢弃,不等待Broker确认。本案例中client.publish()的第三个参数设为false即表示QoS 0。若需观察更明显的丢失效果,可增大发布频率或使用不稳定的网络环境(如移动热点)。实际工程中,QoS 0适用于传感器数据上报等允许偶发丢失的场景,而QoS 1/2则用于需要可靠投递的控制指令。