MQTT QOS & Retained Message

项目终于基本完成了,记录一下,由于客户端误设置了发布保留消息,导致服务器每次上线都会收到客户端最后一条消息,先去解读并改了QOS的设置,并没有用,然后才发现有Retained Message的设置,直接false就可以了。

Qos 0/1/2的区别实测

最多一次的传输 消息是基于TCP/IP网络传输的。没有回应,在协议中也没有定义重传的语义。消息可能到达服务器1次,也可能根本不会到达。

在这里插入图片描述

至少一次的传输 服务器接收到消息会被确认,通过传输一个PUBACK信息。如果有一个可以辨认的传输失败,无论是通讯连接还是发送设备,还是过了一段时间确认信息没有收到,发送方都会将消息头的DUP位置1,然后再次发送消息。消息最少一次到达服务器。SUBSCRIBE和UNSUBSCRIBE都使用level 1 的QoS。 如果客户端没有接收到PUBACK信息(无论是应用定义的超时,还是检测到失败然后通讯session重启),客户端都会再次发送PUBLISH信息,并且将DUP位置1。 当它从客户端接收到重复的数据,服务器重新发送消息给订阅者,并且发送另一个PUBACK消息。

笔者做了一个实现消费端阻塞2秒消费一个内容,发布端1秒发布一个内容,等EMQ的最大拥塞使用完了之后消息在EMQ缓存的会后就会出现很多的重复消息

在这里插入图片描述
只有一次的传输 在QoS level 1上附加的协议流保证了重复的消息不会传送到接收的应用。这是最高级别的传输,当重复的消息不被允许的情况下使用。这样增加了网络流量,但是它通常是可以接受的,因为消息内容很重要。 QoS level 2在消息头有Message ID。

在C语言中实现MQTTQoS 2对话控制流程需要手动处理消息的确认和释放流程。以下是基于MQTT协议的QoS 2实现步骤和代码示例,使用开源库如 **Paho MQTT C** 或 **Mosquitto** 可以简化开发。 --- ### **QoS 2 对话控制流程(C语言实现)** 1. **发布者发送PUBLISH(QoS 2)** - 设置 `QoS=2` 和 `Packet Identifier`。 - 等待 `PUBREC` 响应。 2. **代理返回PUBREC** - 发布者收到 `PUBREC` 后,存储消息并发送 `PUBREL`。 3. **发布者发送PUBREL** - 通知代理释放消息存储。 - 等待 `PUBCOMP` 确认。 4. **代理返回PUBCOMP** - 发布者收到 `PUBCOMP` 后,释放本地存储的消息。 --- ### **代码示例(基于Paho MQTT C库)** ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <MQTTClient.h> #define ADDRESS "tcp://broker.example.com:1883" #define CLIENTID "ExampleClientQoS2" #define TOPIC "test/qos2" #define QOS 2 #define TIMEOUT 10000L volatile MQTTClient_deliveryToken deliveredtoken; void delivered(void *context, MQTTClient_deliveryToken dt) { printf("Message with token value %d delivery confirmed\n", dt); deliveredtoken = dt; } int main(int argc, char* argv[]) { MQTTClient client; MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; MQTTClient_message pubmsg = MQTTClient_message_initializer; MQTTClient_token token; int rc; // 创建客户端 rc = MQTTClient_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL); if (rc != MQTTCLIENT_SUCCESS) { printf("Failed to create client, return code %d\n", rc); exit(EXIT_FAILURE); } // 设置回调函数 rc = MQTTClient_setCallbacks(client, NULL, NULL, delivered, NULL); if (rc != MQTTCLIENT_SUCCESS) { printf("Failed to set callbacks, return code %d\n", rc); MQTTClient_destroy(&client); exit(EXIT_FAILURE); } // 连接代理 conn_opts.keepAliveInterval = 20; conn_opts.cleansession = 1; if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) { printf("Failed to connect, return code %d\n", rc); MQTTClient_destroy(&client); exit(EXIT_FAILURE); } // 发布消息(QoS 2) pubmsg.payload = "Hello QoS 2"; pubmsg.payloadlen = (int)strlen(pubmsg.payload); pubmsg.qos = QOS; pubmsg.retained = 0; deliveredtoken = 0; rc = MQTTClient_publishMessage(client, TOPIC, &pubmsg, &token); if (rc != MQTTCLIENT_SUCCESS) { printf("Failed to publish message, return code %d\n", rc); MQTTClient_disconnect(client, 10000); MQTTClient_destroy(&client); exit(EXIT_FAILURE); } printf("Waiting for message delivery confirmation (QoS 2)...\n"); while (deliveredtoken != token) { // 等待PUBCOMP确认 } // 断开连接 MQTTClient_disconnect(client, 10000); MQTTClient_destroy(&client); return rc; } ``` --- ### **关键点说明** 1. **`PUBREC` 和 `PUBCOMP` 的处理** - Paho库自动处理 `PUBREC` 和 `PUBCOMP` 的交互,开发者只需关注 `delivered` 回调。 - 若需手动实现,需维护一个消息状态机(如 `PUBLISH_SENT → PUBREC_RECEIVED → PUBREL_SENT → PUBCOMP_RECEIVED`)。 2. **消息重发机制** - 如果 `PUBREC` 或 `PUBCOMP` 超时未收到,需重发 `PUBLISH` 或 `PUBREL`。 3. **存储管理** - 发布者需保存消息副本,直到收到 `PUBCOMP`。 --- ### **手动实现QoS 2的简化逻辑(无库)** ```c // 伪代码:手动实现QoS 2状态机 typedef enum { WAIT_PUBREC, WAIT_PUBCOMP } QoS2State; void handle_publish_ack(int packet_id, int ack_type) { static QoS2State state = WAIT_PUBREC; if (ack_type == PUBREC) { if (state == WAIT_PUBREC) { send_pubrel(packet_id); // 发送PUBREL state = WAIT_PUBCOMP; } } else if (ack_type == PUBCOMP) { if (state == WAIT_PUBCOMP) { free_message(packet_id); // 释放存储的消息 state = WAIT_PUBREC; // 重置状态 } } } ``` --- ### **相关问题** 1. 在C语言中,如何处理QoS 2消息的超时重传? 2. 如果代理未返回`PUBREC`,发布者应如何重试? 3. 手动实现QoS 2时,如何管理消息的存储和释放? 4. Paho MQTT C库是否完全支持QoS 2的异步确认? 5. QoS 2在嵌入式设备中的资源消耗如何优化?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值