MQTT协议---EMQX基础应用~~~
一、前言
在物联网项目中必不可少使用mqtt协议,不同平台、终端设备都要使用mqtt交互数据,但是mqtt协议的使用必然会涉及到mqtt的broker的使用,和数据持久化。
二、MQTT协议
1、简介
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议)
,是一种基于发布/订阅模式的"轻量级
"通讯协议,它和 Modbus TCP
一样都是基于 TCP/IP 之上的应用层协议。
物联网设备通信有一些问题需要针对性的解决:网络环境复杂而不可靠、硬件内存和闪存容量小、处理器能力有限。MQTT 协议就是为了解决遇到的这些问题而创建的;
MQTT 最小报文仅为 2 个字节,比 HTTP 占用更少网络开销,MQTT 基于发布订阅模式,HTTP 基于请求响应。
MQTT 和消息队列的很多行为和特性非常接近, 比如都采用发布/订阅模式,但是他们面向的场景却 有着显著的不同。消息队列主要用于服务端应用之间的消息存储与转发,这类场景往往数据量大但客户端 数量少。MQTT 是一种消息传输协议,主要用于物联网设备之间的消息传递,这类场景的特点是海量的设备接入、管理与消息传输。
2、MQTT消息服务质量等级
MQTT协议可以对消息设置三种不同的服务质量等级,分别是:
1)QoS=0:最多发送一次,订阅方不会发送接收到消息的响应,发布方也不会重新发送消息,消息可能会丢失;
2)QoS=1:最少发送一次,订阅方接收到消息之后发送响应给发布方,如果发布方没收到响应会重新发送消息,直到接收到响应为止,消息可能会重复;
3)QoS=2:保证只有一次,订阅方不会重复接收到消息,也不会丢失消息。发布方和订阅方之间需要进行两次请求响应确认消息传输,保证相同消息只接收一次,QoS为2时消耗网络资源也最多;
3、MQTT 主题通配符
MQTT 通配符包含单层通配符 +
和多层通配符#
,主要用于客户端一次订阅多个主题。在发布的时候不能用通配符下发到多个主题中;
单层通配符适用于单个主题层级匹配的通配符,单层通配符必须占据整个层级才能生效;
多层通配符适用于主题匹配任意层级的通配符,多层通配符表示它的父级和任意数量的子层级,多层通配符必须单独占据一个层级才能生效;
三、EMQX简介
EMQX 是一款「无限连接,任意集成,随处运行」的大规模分布式物联网接入平台,同时作为一个高性能、可扩展的 MQTT
消息服务器,它可以为物联网(IoT)应用提供可靠的实时消息传输和设备连接解决方案。
EMQX官网:https://docs.emqx.com/
版本:
EMQX分为开源版本和企业版本,我们主要分享开源版本的使用,会话持久化是 EMQX 企业版功能
。
会话和持久存储:
- 会话:会话是 EMQX 为每个客户端连接创建的轻量级进程。会话负责执行 MQTT
标准中对消息服务器(broker)所要求的行为。这些行为包括初始连接、订阅和取消订阅主题以及消息分发。 - 持久存储:持久存储是 EMQX 内部使用的数据库。会话可以利用持久存储保存其状态和发送到主题的 MQTT消息。支持持久存储的数据库引擎使用 RocksDB 将数据保存到磁盘,并通过 Raft 在集群中一致地复制数据。需要注意的是,持久存储与 持久会话 是不同的概念。
四、EMQX环境搭建
1、运行以下命令获取 Docker 镜像:
- docker pull emqx/emqx:5.8.0
2、启动容器
docker run -d --name emqx \
-p 1883:1883 -p 8083:8083 \
-p 8084:8084 -p 8883:8883 \
-p 18083:18083 \
-v $PWD/data:/opt/emqx/data \
-v $PWD/log:/opt/emqx/log \
emqx/emqx:5.8.0
3、mqttx客户端
下载地址:https://mqttx.app/zh/downloads
4、功能验证
数据发送:
数据接收:
五、springboot集成
pom.xml依赖
<dependency>
<groupId>org.eclipse.paho</groupId>
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
<version>1.2.2</version>
</dependency>
Producer.java
package com.sk.proxytest.mqtt;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
//@Configuration
public class Producer {
@PostConstruct
private void producer(){
String pubTopic = "testtopic";
String content = "Hello World";
int qos = 2;
String broker = "tcp://159.75.225.251:1883";
String clientId = "emqx_test";
MemoryPersistence persistence = new MemoryPersistence();
try {
MqttClient client = new MqttClient(broker, clientId, persistence);
// MQTT 连接选项
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setUserName("emqx_test");
connOpts.setPassword("emqx_test_password".toCharArray());
// 保留会话
connOpts.setCleanSession(true);
// 设置回调
client.setCallback(new OnMessageCallback());
// 建立连接
System.out.println("Connecting to broker: " + broker);
client.connect(connOpts);
// 消息发布所需参数
MqttMessage message = new MqttMessage(content.getBytes());
message.setQos(qos);
client.publish(pubTopic, message);
System.out.println("Message published");
client.disconnect();
System.out.println("Disconnected");
client.close();
System.exit(0);
} catch (MqttException me) {
System.out.println("reason " + me.getReasonCode());
System.out.println("msg " + me.getMessage());
System.out.println("loc " + me.getLocalizedMessage());
System.out.println("cause " + me.getCause());
System.out.println("excep " + me);
me.printStackTrace();
}
}
}
程序执行结果:
2024-09-08 17:24:48.479 INFO 14732 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 919 ms
Connecting to broker: tcp://159.75.225.251:1883
Message published
deliveryComplete---------true
Disconnected
消费工具:
Consumer.java
package com.sk.proxytest.mqtt;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
//@Configuration
public class Consumer {
@PostConstruct
private void producer(){
new Thread(new Runnable() {
@Override
public void run() {
test();
}
}).start();
}
public void test(){
String subTopic = "testtopic";
String broker = "tcp://159.75.225.251:1883";
String clientId = "emqx_test2";
MemoryPersistence persistence = new MemoryPersistence();
try {
MqttClient client = new MqttClient(broker, clientId, persistence);
// MQTT 连接选项
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setUserName("emqx_test");
connOpts.setPassword("emqx_test_password".toCharArray());
// 保留会话
connOpts.setCleanSession(true);
// 设置回调
client.setCallback(new OnMessageCallback());
// 建立连接
System.out.println("Connecting to broker: " + broker);
client.connect(connOpts);
while (true) {
try {
client.subscribe(subTopic);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (MqttException me) {
System.out.println("reason " + me.getReasonCode());
System.out.println("msg " + me.getMessage());
System.out.println("loc " + me.getLocalizedMessage());
System.out.println("cause " + me.getCause());
System.out.println("excep " + me);
me.printStackTrace();
}
}
}
程序执行结果:
2024-09-08 17:26:40.446 INFO 10460 --- [ main] com.sk.proxytest.ProxyTestApplication : Started ProxyTestApplication in 2.076 seconds (JVM running for 3.006)
接收消息主题:testtopic
接收消息Qos:0
接收消息内容:{
"msg": "hello1111"
}
接收消息主题:testtopic
接收消息Qos:0
接收消息内容:{
"msg": "hello1111"
}
注:在实际应用中可以使用mqtt连接创建工厂或者连接池
----------------------------------👇👇👇注:更多信息请关注公众号获取
👇👇👇-------------------------------------------