项目全部代码地址:https://github.com/Tom-shushu/work-study.gitmqtt-emqt 项目)

先看我们最后实现的一个效果

1.手机端向主题 topic111 发送消息,并接收。(手机测试工具名称:MQTT调试器)

2.控制台打印

MQTT基本简介

MQTT 是用于物联网 (IoT) 的 OASIS 标准消息传递协议。它被设计为一种极其轻量级的发布/订阅消息传输,非常适合连接具有小代码足迹和最小网络带宽的远程设备。

MQTT协议简介

MQTT 是客户端服务器发布/订阅消息传输协议。它重量轻、开放、简单,并且易于实施。这些特性使其非常适合在许多情况下使用,包括受限制的环境,例如机器对机器 (M2M) 和物联网 (IoT) 环境中的通信,其中需要小代码足迹和/或网络带宽非常宝贵。

该协议通过 TCP/IP 或其他提供有序、无损、双向连接的网络协议运行。其特点包括:

·         使用发布/订阅消息模式,提供一对多的消息分发和应用程序的解耦。

·         与有效负载内容无关的消息传输。

·         消息传递的三种服务质量:

o    “最多一次”,根据操作环境的最大努力传递消息。可能会发生消息丢失。例如,此级别可用于环境传感器数据,其中单个读数是否丢失并不重要,因为下一个读数将很快发布。

o    “至少一次”,保证消息到达但可能出现重复。

o    “Exactly once”,保证消息只到达一次。例如,此级别可用于重复或丢失消息可能导致应用不正确费用的计费系统。

·         最小化传输开销和协议交换以减少网络流量。

·         发生异常断开时通知相关方的机制。

EMQX简介

通过开放标准物联网协议 MQTT、CoAP 和 LwM2M 连接任何设备。使用 EMQX Enterprise 集群轻松扩展到数千万并发 MQTT 连接。

并且EMQX还是开源的,又支持集群,所以还是一个比较不错的选择

EMQX集群搭建

前期准备:

1.两台服务器:我的两个服务器一台是腾讯云、一台是阿里云的(不要问为什么,薅羊毛得来的)咱们暂且叫他们 mqtt_service_aliyun和

 mqtt_service_txyun 吧。
2.一个域名: mqtt.zhouhong.icu

安装开始

1.分别在两台服务器上执行以下操作进行安装(如果是单机:只需要进行下面1、2操作就安装完成了)
## 1.下载
wget https://www.emqx.com/zh/downloads/broker/4.4.4/emqx-4.4.4-otp24.1.5-3-el8-amd64.rpm
## 2.安装
sudo yum install emqx-4.4.4-otp24.1.5-3-el8-amd64.rpm
## 3.修改配置文件
vim /etc/emqx/emqx.conf
## 4.修改以下内容
## 注意node.name是当前这台服务器名称
node.name = mqtt_service_txyun@xxx.xx.xxx.xx
cluster.static.seeds = mqtt_service_txyun@xxx.xx.xxx.xx,mqtt_service_aliyun@xxx.xx.xxx.xx
cluster.discovery = static
cluster.name = my-mqtt-cluster
2.分别启动两台服务器的EMQX
sudo emqx start
3.到浏览器输入 http://xxx.xx.xxx.xxx:18083/ 查看(随便一台都可以,默认账号admin 密码public),注意打开18083,1883 安全组

4.nginx负载均衡

nginx搭建很简单略过,大家只需要修改以下nginx.conf里面的内容即可

stream {
upstream mqtt.zhouhong.icu {
zone tcp_servers 64k;
hash $remote_addr;
server xxx.xx.xxx.xx:1883 weight=1 max_fails=3 fail_timeout=30s;
server xxx.xx.xxx.xx:1883 weight=1 max_fails=3 fail_timeout=30s; } server {
listen 8883 ssl;
status_zone tcp_server;
proxy_pass mqtt.zhouhong.icu;
proxy_buffer_size 4k;
ssl_handshake_timeout 15s;
ssl_certificate /etc/nginx/7967358_www.mqtt.zhouhong.icu.pem;
ssl_certificate_key /etc/nginx/7967358_www.mqtt.zhouhong.icu.key;
}
}

与SpringBoot集成并实现服务器端监控对应topic下的消息

1.项目搭建

  • 引入MQTT相关jar包
        <dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mqtt</artifactId>
</dependency>
  • yml配置文件 (如果大家没搭建好的话,可以直接使用我搭建的这个)
server:
port: 8080 mqtt:
 ## 单机版--只需要把域名改为ip既可 
hostUrl: tcp://mqtt.zhouhong.icu:1883
username: admin
password: public
## 服务端 clientId (发送端自己定义)
clientId: service_client_id
cleanSession: true
reconnect: true
timeout: 100
keepAlive: 100
defaultTopic: topic111
qos: 0
  • 属性配置
/**
* description:
* date: 2022/6/16 15:51
* @author: zhouhong
*/
@Component
@ConfigurationProperties("mqtt")
@Data
public class MqttProperties { /**
* 用户名
*/
private String username; /**
* 密码
*/
private String password; /**
* 连接地址
*/
private String hostUrl; /**
* 客户端Id,同一台服务器下,不允许出现重复的客户端id
*/
private String clientId; /**
* 默认连接主题
*/
private String topic; /**
* 超时时间
*/
private int timeout; /**
* 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端
* 发送个消息判断客户端是否在线,但这个方法并没有重连的机制
*/
private int keepAlive; /**
* 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连
* 接记录,这里设置为true表示每次连接到服务器都以新的身份连接
*/
private Boolean cleanSession; /**
* 是否断线重连
*/
private Boolean reconnect; /**
* 连接方式
*/
private Integer qos;
}
  • 发送消息回调
/**
* description: 发生消息成功后 的 回调
* date: 2022/6/16 15:55
*
* @author: zhouhong
*/
@Component
@Log4j2
public class MqttSendCallBack implements MqttCallbackExtended { /**
* 客户端断开后触发
* @param throwable
*/
@Override
public void connectionLost(Throwable throwable) {
log.info("发送消息回调: 连接断开,可以做重连");
} /**
* 客户端收到消息触发
*
* @param topic 主题
* @param mqttMessage 消息
*/
@Override
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
log.info("发送消息回调: 接收消息主题 : " + topic);
log.info("发送消息回调: 接收消息内容 : " + new String(mqttMessage.getPayload()));
} /**
* 发布消息成功
*
* @param token token
*/
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
String[] topics = token.getTopics();
for (String topic : topics) {
log.info("发送消息回调: 向主题:" + topic + "发送消息成功!");
}
try {
MqttMessage message = token.getMessage();
byte[] payload = message.getPayload();
String s = new String(payload, "UTF-8");
log.info("发送消息回调: 消息的内容是:" + s);
} catch (MqttException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} /**
* 连接emq服务器后触发
*
* @param b
* @param s
*/
@Override
public void connectComplete(boolean b, String s) {
log.info("--------------------ClientId:"
+ MqttAcceptClient.client.getClientId() + "客户端连接成功!--------------------");
}
}
  • 接收消息回调
/**
* description: 接收消息后的回调
* date: 2022/6/16 15:52
*
* @author: zhouhong
*/
@Component
@Log4j2
public class MqttAcceptCallback implements MqttCallbackExtended { @Resource
private MqttAcceptClient mqttAcceptClient; /**
* 客户端断开后触发
*
* @param throwable
*/
@Override
public void connectionLost(Throwable throwable) {
log.info("接收消息回调: 连接断开,可以做重连");
if (MqttAcceptClient.client == null || !MqttAcceptClient.client.isConnected()) {
log.info("接收消息回调: emqx重新连接....................................................");
mqttAcceptClient.reconnection();
}
} /**
* 客户端收到消息触发
*
* @param topic 主题
* @param mqttMessage 消息
*/
@Override
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
log.info("接收消息回调: 接收消息主题 : " + topic);
log.info("接收消息回调: 接收消息内容 : " + new String(mqttMessage.getPayload()));
} /**
* 发布消息成功
*
* @param token token
*/
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
String[] topics = token.getTopics();
for (String topic : topics) {
log.info("接收消息回调: 向主题:" + topic + "发送消息成功!");
}
try {
MqttMessage message = token.getMessage();
byte[] payload = message.getPayload();
String s = new String(payload, "UTF-8");
log.info("接收消息回调: 消息的内容是:" + s);
} catch (MqttException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} /**
* 连接emq服务器后触发
*
* @param b
* @param s
*/
@Override
public void connectComplete(boolean b, String s) {
log.info("--------------------ClientId:"
+ MqttAcceptClient.client.getClientId() + "客户端连接成功!--------------------");
// 以/#结尾表示订阅所有以test开头的主题
// 订阅所有机构主题
mqttAcceptClient.subscribe("topic111", 0);
}
}
  • 发消息
/**
* description: 发送消息
* date: 2022/6/16 16:01
*
* @author: zhouhong
*/
@Component
public class MqttSendClient { @Autowired
private MqttSendCallBack mqttSendCallBack; @Autowired
private MqttProperties mqttProperties; public MqttClient connect() {
MqttClient client = null;
try {
String uuid = UUID.randomUUID().toString().replaceAll("-","");
client = new MqttClient(mqttProperties.getHostUrl(),uuid , new MemoryPersistence());
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(mqttProperties.getUsername());
options.setPassword(mqttProperties.getPassword().toCharArray());
options.setConnectionTimeout(mqttProperties.getTimeout());
options.setKeepAliveInterval(mqttProperties.getKeepAlive());
options.setCleanSession(true);
options.setAutomaticReconnect(false);
try {
// 设置回调
client.setCallback(mqttSendCallBack);
client.connect(options);
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
return client;
} /**
* 发布消息
* 主题格式: server:report:$orgCode(参数实际使用机构代码)
*
* @param retained 是否保留
* @param pushMessage 消息体
*/
public void publish(boolean retained, String topic, String pushMessage) {
MqttMessage message = new MqttMessage();
message.setQos(mqttProperties.getQos());
message.setRetained(retained);
message.setPayload(pushMessage.getBytes());
MqttClient mqttClient = connect();
try {
mqttClient.publish(topic, message);
} catch (MqttException e) {
e.printStackTrace();
} finally {
disconnect(mqttClient);
close(mqttClient);
}
} /**
* 关闭连接
*
* @param mqttClient
*/
public static void disconnect(MqttClient mqttClient) {
try {
if (mqttClient != null) {
mqttClient.disconnect();
}
} catch (MqttException e) {
e.printStackTrace();
}
} /**
* 释放资源
*
* @param mqttClient
*/
public static void close(MqttClient mqttClient) {
try {
if (mqttClient != null) {
mqttClient.close();
}
} catch (MqttException e) {
e.printStackTrace();
}
}
}
  • 接收消息
/**
* description: 服务器段端连接订阅消息、监控topic
* date: 2022/6/16 15:52
*
* @author: zhouhong
*/
@Component
@Log4j2
public class MqttAcceptClient { @Autowired
@Lazy
private MqttAcceptCallback mqttAcceptCallback; @Autowired
private MqttProperties mqttProperties; public static MqttClient client; private static MqttClient getClient() {
return client;
} private static void setClient(MqttClient client) {
MqttAcceptClient.client = client;
} /**
* 客户端连接
*/
public void connect() {
MqttClient client;
try {
// clientId 使用服务器 yml里面配置的 clientId
client = new MqttClient(mqttProperties.getHostUrl(), mqttProperties.getClientId(), new MemoryPersistence());
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(mqttProperties.getUsername());
options.setPassword(mqttProperties.getPassword().toCharArray());
options.setConnectionTimeout(mqttProperties.getTimeout());
options.setKeepAliveInterval(mqttProperties.getKeepAlive());
options.setAutomaticReconnect(mqttProperties.getReconnect());
options.setCleanSession(mqttProperties.getCleanSession());
MqttAcceptClient.setClient(client);
try {
// 设置回调
client.setCallback(mqttAcceptCallback);
client.connect(options);
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
} /**
* 重新连接
*/
public void reconnection() {
try {
client.connect();
} catch (MqttException e) {
e.printStackTrace();
}
} /**
* 订阅某个主题
*
* @param topic 主题
* @param qos 连接方式
*/
public void subscribe(String topic, int qos) {
log.info("==============开始订阅主题==============" + topic);
try {
client.subscribe(topic, qos);
} catch (MqttException e) {
e.printStackTrace();
}
} /**
* 取消订阅某个主题
*
* @param topic
*/
public void unsubscribe(String topic) {
log.info("==============开始取消订阅主题==============" + topic);
try {
client.unsubscribe(topic);
} catch (MqttException e) {
e.printStackTrace();
}
}
}
  • 服务端启动时连接订阅主题并监控
/**
* description: 启动后连接 MQTT 服务器, 监听 mqtt/my_topic 这个topic发送的消息
* date: 2022/6/16 15:57
* @author: zhouhong
*/
@Configuration
public class MqttConfig { @Resource
private MqttAcceptClient mqttAcceptClient; @Bean
public MqttAcceptClient getMqttPushClient() {
mqttAcceptClient.connect();
return mqttAcceptClient;
}
}
  • 发消息控制类
/**
* description: 发消息控制类
* date: 2022/6/16 15:58
*
* @author: zhouhong
*/
@RestController
public class SendController { @Resource
private MqttSendClient mqttSendClient; @PostMapping("/mqtt/sendmessage")
public void sendMessage(@RequestBody SendParam sendParam) {
mqttSendClient.publish(false,sendParam.getTopic(),sendParam.getMessageContent());
}
}

2.测试

  • postman调用发消息接口

  • 控制台日志

  • 使用另外一个移动端MQTT调试工具测试
  1. 手机端向主题 topic111 发送消息,并接收。

  2. 控制台打印

物联网微消息队列MQTT介绍-EMQX集群搭建以及与SpringBoot整合的更多相关文章

  1. RabbitMQ镜像队列集群搭建、与SpringBoot整合

    镜像模式 集群模式非常经典的就是Mirror镜像模式,保证100%数据不丢失,在实际工作中也是用的最多的,并且实现集群比较的简单. Mirror镜像队列,目的是为了保证 RabbitMQ 数据的高可靠 ...

  2. kafka集群搭建及结合springboot使用

    1.场景描述 因kafka以前用的不多,只往topic中写入和读取过数据,这次刚好又要用到,记录下kafka集群搭建及结合springboot使用. 2. 解决方案 2.1 简单介绍 (一)关于kaf ...

  3. 2. zookeeper介绍及集群搭建

    ZooKeeper 概述 Zookeeper 是一个分布式协调服务的开源框架. 主要用来解决分布式集群中 应用系统的一致性问题,例如怎样避免同时操作同一数据造成脏读的问题. ZooKeeper 本质上 ...

  4. Hadoop介绍及集群搭建

    简介 Hadoop 是 Apache 旗下的一个用 java 语言实现开源软件框架,是一个开发和运行处理大规模数据的软件平台.允许使用简单的编程模型在大量计算机集群上对大型数据集进行分布式处理.它的核 ...

  5. Kafka介绍及集群搭建

    简介 Kafka是一个开源的,分布式的,高吞吐量的消息系统.随着Kafka的版本迭代,日趋成熟.大家对它的使用也逐步从日志系统衍生到其他关键业务领域.特别是其超高吞吐量的特性,在互联网领域,使用越来越 ...

  6. Apache Spark介绍及集群搭建

    简介 Spark是一个针对于大规模数据处理的统一分析引擎.其处理速度比MapReduce快很多.其特征有: 1.速度快 spark比mapreduce在内存中快100x,比mapreduce在磁盘中快 ...

  7. 高可用Hadoop平台-HBase集群搭建

    1.概述 今天补充一篇HBase集群的搭建,这个是高可用系列遗漏的一篇博客,今天抽时间补上,今天给大家介绍的主要内容目录如下所示: 基础软件的准备 HBase介绍 HBase集群搭建 单点问题验证 截 ...

  8. [spark]-Spark2.x集群搭建与参数详解

    在前面的Spark发展历程和基本概念中介绍了Spark的一些基本概念,熟悉了这些基本概念对于集群的搭建是很有必要的.我们可以了解到每个参数配置的作用是什么.这里将详细介绍Spark集群搭建以及xml参 ...

  9. JAVAEE——宜立方商城08:Zookeeper+SolrCloud集群搭建、搜索功能切换到集群版、Activemq消息队列搭建与使用

    1. 学习计划 1.solr集群搭建 2.使用solrj管理solr集群 3.把搜索功能切换到集群版 4.添加商品同步索引库. a) Activemq b) 发送消息 c) 接收消息 2. 什么是So ...

随机推荐

  1. Mybatis映射文件动态SQL语句-02

    foreach UserMapper.xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYP ...

  2. 用户USER_HZ与内核HZ的值

    HZ和Jiffies系统定时器timer能够以可编程的方式设定频率,来中断cpu处理器.此频率即hz,为每秒的定时器节拍(tick)数, 对应着内核变量HZ.选择合适的HZ值需要权衡. tick为两个 ...

  3. 『现学现忘』Git基础 — 2、Git和SVN的区别

    1.Git和SVN的区别 (1)SVN(集中式版本管理系统) 集中式的版本控制系统都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者 ...

  4. Kubernetes部署单元-Pod

    在 k8s 搞出 pod 概念的时候,其实 docker 官方就已经推出自己的容器编排应用 swarm.这一套服务可以帮助在不同节点上的容器,进行统一的管理,主要针对容器的启停,运维,还有部署,注意我 ...

  5. SpringBoot 入门及配置

    1.首先创建Maven文件,右键单击鼠标,others搜索Maven,点击Maven Project 2.点击下一步,打上勾下一步,输入包名和项目名称 3.第三步修改pom.xml导入Maven依赖M ...

  6. Web项目部署指南

    Web项目部署指南 本文记录了部署Vue项目到阿里云服务器上的过程,其中云服务器的操作系统是CentOS 7,Web服务器用的是nginx.因为项目涉及发送异步请求,而由Flask编写的后端应用监听的 ...

  7. Hyperledger Fabric 通道配置文件和容器环境变量详解

    摘要 Fabric 网络启动的过程中需要进行大量配置,新学时对各个配置的作用一无所知,这导致我曾在网络出问题时先对配置文件的内容进行排列组合后再祈祷它能在某个时刻顺利运行,因此掌握 fabric 各个 ...

  8. delaycall.js 修改表单延迟自动提交的 jQuery / Zepto 插件

    delaycall.js delaycall 是一个 jQuery / Zepto 插件,用于在用户完成某项操作后,延迟指定秒数后自动调动指定函数.如用户输入完内容后,延迟1秒,自动提交表单. Git ...

  9. html_学习所有标签使用

    <!DOCTYPE html><!--声明为HTML5文档--><html lang="en"><head><!-- 页面表头 ...

  10. springmvc-02(配置版与注解版区别)

    首先,我们来看配置版和注解版的相同步骤: 1.新建一个Moudle , springmvc-02-hello , 添加web的支持! 2.确定导入了SpringMVC 的依赖! 3.配置web.xml ...