mqtt - 关键参数
MQTT 协议
MQTT 协议是一种基于发布/订阅模式的轻量级通讯协议,由 IBM 在 1999 年发布。
它构建于 TCP/IP 协议之上,适用于低带宽、低性能的网络环境,广泛应用于物联网、小型设备、移动应用等领域。
关键参数
发送消息的时候,需要注意两个参数:消息保留(retain)、消息质量(QoS);
连接配置项,重点注意:CleanSession;
消息保留 retain
默认情况下,如果接收方没收到消息,会立即丢弃消息;
发布消息时,如果将 retain 标志位设置为 true,MQTT 服务器会将该消息保存起来;
一个 topic 只能有一条 retain 消息,换种说法,就是服务器每次只保留最新的一条消息;
这个机制,可以确保当客户端连接到 MQTT 服务器时,可以立即收到该 topic 的最新状态。
服务质量 QoS
服务质量(Quality of Service)
最多交付一次(AT_MOST_ONCE,值为 0)
- 无消息确认:发送者发送消息后,不需要确认消息是否到达接收者。
- 无重试:如果消息在传输过程中丢失,发送者不会再次发送该消息。
- 风险:消息可能丢失。在网络不稳定或发生传输错误时,消息可能不会到达接收者。
- 适用场景:适合对消息丢失不敏感的应用,例如发送传感器数据,实时监测数据,或日志记录。
至少交付一次(AT_LEAST_ONCE,值为 1)
- 无消息确认:发送者发送消息后,不需要确认消息是否到达接收者。
- 无重试:如果消息在传输过程中丢失,发送者不会再次发送该消息。
- 风险:消息可能丢失。在网络不稳定或发生传输错误时,消息可能不会到达接收者。
- 适用场景:适合对消息丢失不敏感的应用,例如发送传感器数据,实时监测数据,或日志记录。
仅交付一次(EXACTLY_ONCE,值为 2)
- 高级消息确认:通过复杂的四步握手过程(PUBREC、PUBREL、PUBCOMP),确保消息仅传输一次,避免重复。
- 支持重试:如果在任何一步未收到确认,发送者和接收者都会重试相应步骤,直到完成整个确认过程。
- 风险:消息不会丢失或重复。确保了消息在传输中不会丢失,并且不会重复到达接收者。
- 适用场景:适合不能接受消息丢失或重复的应用,例如金融交易、订单处理等关键业务场景。
client 断线恢复(持久化会话)
原文:https://baijiahao.baidu.com/s?id=1758335268020607220&wfr=spider&for=pc
如果启用会话保持,服务器记住该消费者,保留会话信息。
消费者重新上线时,无需重新订阅 topic,直接消费消息(包括离线消息)。
清理会话(CleanSession)标志被设置为 false
服务端必须基于当前会话(使用客户端标识符识别)的状态恢复与客户端的通信。如果没有与这个客户端标识符关联的会话,服务端必须创建一个新的会话。在连接断开之后,当连接断开后,客户端和服务端必须保存会话信息。
当清理会话标志为0的会话连接断开之后,服务端必须将之后的QoS 1和QoS 2级别的消息保存为会话状态的一部分,如果这些消息匹配断开连接时客户端的任何订阅。服务端也可以保存满足相同条件的QoS 0级别的消息
清理会话(CleanSession)标志被设置为 true
客户端和服务端必须丢弃之前的任何会话并开始一个新的会话。会话仅持续和网络连接同样长的时间。与这个会话关联的状态数据不能被任何之后的会话重用
注意:如果需要持久化会话,就不能使用动态的 Client ID 了。
案例 - mqtt-client 包实现
这个包的缺点,就是网上案例极少,推荐使用 mqttv3 包。
好处就是代码简单,关键参数一目了然。
Maven 依赖
<dependency>
<groupId>org.fusesource.mqtt-client</groupId>
<artifactId>mqtt-client</artifactId>
<version>1.16</version>
</dependency>
代码
import org.fusesource.hawtbuf.AsciiBuffer;
import org.fusesource.hawtbuf.UTF8Buffer;
import org.fusesource.mqtt.client.FutureConnection;
import org.fusesource.mqtt.client.MQTT;
import org.fusesource.mqtt.client.QoS;
/**
* 发生 MQTT 消息
*
* @author Mr.css
* @version 2024-10-15 9:16
*/
public class MQTTSender {
public static void main(String[] args) throws Exception {
MQTT mqtt = new MQTT();
mqtt.setHost("localhost", 1883);
mqtt.setUserName("admin");
mqtt.setPassword("admin");
FutureConnection connection = mqtt.futureConnection();
connection.connect().await();
UTF8Buffer topic = new UTF8Buffer("mqtt");
int messageAmount = 1;
while (messageAmount --> 0) {
connection.publish(topic, new AsciiBuffer("test message" + messageAmount), QoS.EXACTLY_ONCE, true);
System.out.println("send message " + messageAmount);
}
connection.disconnect().await();
}
}
import org.fusesource.hawtbuf.UTF8Buffer;
import org.fusesource.mqtt.client.*;
/**
* 接收 MQTT 消息
*
* @author Mr.css
* @version 2024-10-15 9:16
*/
public class MQTTReceiver {
public static void main(String[] args) throws Exception {
MQTT mqtt = new MQTT();
mqtt.setHost("localhost", 1883);
mqtt.setUserName("admin");
mqtt.setPassword("admin");
BlockingConnection connection = mqtt.blockingConnection();
connection.connect();
Topic topic = new Topic("mqtt", QoS.AT_LEAST_ONCE);
// 订阅主题
connection.subscribe(new Topic[]{topic});
// 接收消息
while(true){
Message message = connection.receive();
if (message != null) {
System.out.println("Received: " + new String(message.getPayload()));
} else {
break;
}
}
// 取消订阅并关闭连接
connection.unsubscribe(new UTF8Buffer[]{topic.name()});
connection.disconnect();
}
}
协议与 MQ 之间的关系
从 activemq 的管理界面上看,MQTT 发送出去的数据,也被放到了 topics 中;
因此,可以大胆地尝试一波,把 activemq 的 helloworld 案例拿出来跑跑(TCP协议);
这时候就能发现,使用 MQTT 发送的消息,居然可以用 TCP 协议进行接收。
重新捋一下这些关系
MQTT 服务,是一种行业标准,与平台无关,可以使用 activemq 能实现,也可以用 rabbitmq 实现;
MQ 只是一个数据容器,我们可以用 MQTT 协议发送数据,然后用 TCP 协议获取数据,这没什么问题;
用什么协议发送数据、用什么协议接受数据,客户端用什么代码,这些是完全解耦的,彼此之间没什么必然联系。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
2020-10-31 poi - word合并单元格,拖动之后还原问题