MQTT学习从零到实战:二

本次基于MQTT实现的服务器之一:EMQX 

协议版本:5.0

文档路径:快速开始 | EMQX 5.0 文档

MQTT协议服务器搭建

        本次使用的服务器是EMQX。

        下载地址:立即开始 | EMQX

        从中我们也可以看出,企业版支持数据持久化,需要收费。如果是对数据没有太高要求的话,可以使用免费版。开源版个人认为适用场景:实现手机远程控制家中的灯光、门窗、温度等设备。设备的心跳检测等对数据要求稍低的场景。例如心跳少跳一次或者温度少发送几次,不会影响整体业务的需求。

我们以Windows版本为例:

访问:http://localhost:18083/    默认账号:admin  默认密码:public

备注:EMQX支持集群,访问控制等等。。具体可以参考文档!此次只介绍一些基础的信息。

MQTT协议属于C/S服务,因此,我们要再启动客户端。

按文档操作客户端:安装 - MQTTX 文档

客户端安装访问后:

这个时候客户端和服务器我们都有了,可以自己参考文档进行相关的配置。

介绍一些名词或功能:

服务端

在发布消息的客户端和订阅的客户端之间充当中介,将所有接收到的消息转发到匹配的订阅客户端。所以有时我们也会直接将服务端称为 Broker。

客户端

使用 MQTT 协议连接到 MQTT 服务端的设备或应用程序。它既可以是发布者,也可以是订阅者,也可以具备这两种身份。

主题

主题被用来标识和区分不同的消息,它是 MQTT 消息路由的基础。发布者可以在发布时指定消息的主题,订阅者则可以选择订阅自己感兴趣的主题来接收相关的消息。

通配符

订阅者可以在订阅的主题中使用通配符来达到一次订阅多个主题的目的。MQTT 提供了单层通配符和多层通配符两种主题通配符,以满足不同的订阅需要。

QoS

MQTT 定义了三种 QoS 等级,来分别提供不同的消息可靠性保证。每条消息都可以在发布时独立设置自己的 QoS。QoS 0 最多交付一次,消息可能丢失;QoS 1 至少交付一次,消息可以保证到达,但是可能重复;QoS 2 只交付一次,消息保证到达,并且不会重复。QoS 越大,消息的传输复杂程度也越高,我们需要根据实际场景来选择合适的 QoS。

会话

QoS 只是设计了消息可靠到达的理论机制,而会话则确保了 QoS 1、2 的协议流程得以真正实现。

会话是客户端与服务端之间的有状态交互,它可以仅持续和网络连接一样长的时间,也可以跨越多个网络连接存在,我们通常将后者称为持久会话。我们可以选择让连接从已存在的会话中恢复,也可以选择从一个全新的会话开始。

保留消息

与普通消息不同,保留消息可以保留在 MQTT 服务器中。任何新的订阅者订阅与该保留消息中的主题匹配的主题时,都会立即接收到该消息,即使这个消息是在它们订阅主题之前发布的。

这使订阅者在上线后可以立即获得数据更新,而不必等待发布者再次发布消息。在某种程度上,我们可以把保留消息当作是一个消息 “云盘” 来使用:随时上传消息到 “云盘”,然后在任意时刻从 “云盘” 获取消息。当然,这个 “云盘” 还有一个主题下只能存储一条最新的保留消息的限制

遗嘱消息

发布订阅模式的特性决定了,除了服务器以外没有客户端能够感知到某个客户端从通信网络中离开。而遗嘱消息则为连接意外断开的客户端提供了向其他客户端发出通知的能力。

客户端可以在连接时向服务器设置自己的遗嘱消息,服务器将在客户端异常断开后立即或延迟一段时间后发布这个遗嘱消息。而订阅了对应遗嘱主题的客户端,将收到这个遗嘱消息,并且采取相应的措施,例如更新该客户端的在线状态等等。

共享订阅

默认情况下,消息会被转发给所有匹配的订阅者。但有时,我们可能希望多个客户端协同处理接收到的消息,以便以水平扩展的方式来提高负载能力。又或者,我们希望为客户端增加一个备份客户端,当主客户端离线时,能够无缝切换到备份客户端继续接收消息,以确保高可用性。。

而 MQTT 的共享订阅特性,则提供了这一能力。我们可以将客户端划分为多个订阅组,消息仍然会被转发给所有订阅组,但每个订阅组内每次只会有一个客户端收到消息。

$SYS 主题

以 $SYS/ 为前缀的主题被保留给服务器用来发布一些特定的消息,比如服务器的运行时间、客户端的上下线事件通知、当前连接的客户端数量等等。我们一般将这些主题称为系统主题,客户端可以订阅这些系统主题来获取服务器的有关信息。

延迟发布

延迟发布可以实现按照用户配置的时间间隔延迟发布消息,当客户端使用特殊主题前缀 $delayed/{DelayInteval} 发布消息时,将触发延迟发布功能。

延迟发布主题的具体格式如下:

$delayed/{DelayInterval}/{TopicName}
  • $delayed:使用 $delay 作为主题前缀的消息都将被视为需要延迟发布的消息。延迟间隔由下一主题层级中的内容决定。
  • {DelayInterval}:指定该 MQTT 消息延迟发布的时间间隔,单位是秒,允许的最大间隔是 4294967 秒。如果 {DelayInterval} 无法被解析为一个整型数字,EMQX 将丢弃该消息,客户端不会收到任何信息。
  • {TopicName}:MQTT 消息的主题名称。

例如:

  • $delayed/15/x/y:15 秒后将 MQTT 消息发布到主题 x/y
  • $delayed/60/a/b:1 分钟后将 MQTT 消息发布到 a/b
  • $delayed/3600/$SYS/topic:1 小时后将 MQTT 消息发布到 $SYS/topic
配置延迟发布
delayed {
    enable = true
    max_delayed_messages = 12435
}

enable:表示开启或关闭延迟发布功能。

max_delayed_messages:表示允许同时存在的延迟发布的消息的最大数量。

自动订阅

自动订阅能够给 EMQX 设置多个规则,在设备成功连接后按照规则为其订阅指定主题,不需要额外发起订阅。

排它订阅

排它订阅允许对主题进行互斥订阅,一个主题同一时刻仅被允许存在一个订阅者,在当前订阅者未取消订阅前,其他订阅者都将无法订阅对应主题。

排它订阅的前缀和示例:

示例前缀真实主题名
$exclusive/t/1$exclusive/t/1

当某个客户端 A 订阅 $exclusive/t/1 后,其他客户端再订阅 $exclusive/t/1 时都会失败,直到 A 取消了对 $exclusive/t/1 的订阅为止。

注意: 排它订阅必须使用 $exclusive/ 前缀,在上面的示例中,其他客户端依然可以通过 t/1 成功进行订阅。

下面提前一些笔者感兴趣的功能,如果想了解其它功能,可以参考文档。

1.在搭配数据桥接的前提下,支持sql数据的处理。向我们展示了字段,内置的SQL函数等等。

2.通过数据桥接,用户可以实时地将消息从 EMQX 发送到外部数据系统。如果使用双向数据桥接,用户还可以从外部数据系统拉取数据并发送到 EMQX 的某个主题。支持常用的Kafka/redis/mysql/mongodb等等。(企业版才支持,收费的)也支持MQTT服务器之间的桥接转发等等。

3.支持SSL/TLS连接

4.支持备份与恢复

EMQX 5.1 引入了一个用户友好的命令行工具用于数据导入和导出。尽管与 EMQX 4.x 中提供的工具类似,但它具有一些显著的差异,并且与之不兼容。

在 EMQX 4.x 中,使用单个 JSON 文件保存 EMQX 配置和内置数据库的所有必要数据。然而,在 EMQX 5.1 中,将导出的数据压缩为 tar 格式的文件,这样可以更高效、更有结构地处理潜在的大量用户数据。

5.速率限制

EMQX 提供对接入速度、消息速度的限制,从入口处避免了系统过载,保证了系统的稳定和可预测的吞吐。  配置文件:emqx.conf

6.告警 

EMQX 内置监控与告警功能,目前支持监控 CPU 占用率、系统与进程的内存占用率、进程数量、规则引擎资源状态、集群脑裂与愈合,并会在发现异常时进行告警。告警的激活与取消都将产生一条警告日志,EMQX 会同时发布一条主题为 $SYS/brokers/<Node>/alarms/activate 或 $SYS/brokers/<Node>/alarms/deactivate 的 MQTT 消息,用户可以通过订阅对应主题来获取告警通知。

7.日志

通过 EMQX 的日志功能,您可查看客户端访问、操作系统或网络异常等问题,如登录错误,异常访问,性能故障等等,并基于日志信息进行问题排查或系统性能优化。

EMQX 支持两种不同的日志输出方式:控制台输出日志和文件输出日志。您可以根据需要选择输出方式或同时启用这两种方式。

为避免日志数据过多或日志写入过慢等问题,EMQX 默认开启了过载保护机制,以确保正常业务不被日志影响。

8.主题监控

EMQX 提供了主题监控功能,可以统计指定主题下的消息收发数量、速率等指标。您可以通过 Dashboard 的 问题分析 -> 主题监控 页面查看和使用这一功能,也可以通过 HTTP API 完成相应操作。

9.集成 Prometheus

可选择提供结合 Prometheus 和 Grafana 实现 EMQX 统计指标可视化。

关于EMQX服务器具体使用,感兴趣的朋友自己去看一下对应的产品文档。 以上只是粗略介绍!

### 回答1: Spring Boot集成MQTT实战 MQTT是一种轻量级的消息传输协议,它适用于物联网设备之间的通信。Spring Boot是一个快速开发框架,它可以帮助我们快速构建应用程序。在本文中,我们将介绍如何使用Spring Boot集成MQTT。 1. 添加依赖 首先,我们需要在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-mqtt</artifactId> <version>5.3.2.RELEASE</version> </dependency> ``` 这个依赖将帮助我们集成MQTT。 2. 配置MQTT连接 在application.properties文件中添加以下配置: ``` spring.mqtt.url=tcp://localhost:1883 spring.mqtt.username= spring.mqtt.password= ``` 这个配置将告诉Spring Boot如何连接到MQTT服务器。 3. 创建MQTT消息处理器 我们需要创建一个MQTT消息处理器来处理接收到的消息。在这个处理器中,我们将定义如何处理接收到的消息。 ``` @Component public class MqttMessageHandler { @ServiceActivator(inputChannel = "mqttInputChannel") public void handleMessage(String message) { System.out.println("Received message: " + message); } } ``` 在这个处理器中,我们使用@ServiceActivator注解来指定输入通道。当有消息到达这个通道时,handleMessage方法将被调用。 4. 创建MQTT消息适配器 我们需要创建一个MQTT消息适配器来发送消息。在这个适配器中,我们将定义如何发送消息。 ``` @Component public class MqttMessageAdapter { @Autowired private MqttPahoClientFactory mqttClientFactory; public void sendMessage(String topic, String message) { MqttMessage mqttMessage = new MqttMessage(message.getBytes()); mqttMessage.setQos(); mqttMessage.setRetained(false); MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler("clientId", mqttClientFactory); messageHandler.setDefaultTopic(topic); messageHandler.handleMessage(mqttMessage); } } ``` 在这个适配器中,我们使用@Autowired注解来注入MqttPahoClientFactory。这个工厂将帮助我们创建MQTT客户端。我们还定义了sendMessage方法来发送消息。 5. 发送和接收消息 现在我们已经准备好发送和接收消息了。我们可以在任何地方使用MqttMessageAdapter来发送消息,例如: ``` @Autowired private MqttMessageAdapter mqttMessageAdapter; public void send() { mqttMessageAdapter.sendMessage("test", "Hello, MQTT!"); } ``` 我们还可以在MqttMessageHandler中处理接收到的消息: ``` @Component public class MqttMessageHandler { @ServiceActivator(inputChannel = "mqttInputChannel") public void handleMessage(String message) { System.out.println("Received message: " + message); } } ``` 6. 运行应用程序 现在我们已经完成了所有的配置和代码编写。我们可以运行应用程序并测试它是否可以发送和接收MQTT消息。 总结 在本文中,我们介绍了如何使用Spring Boot集成MQTT。我们学习了如何配置MQTT连接,创建MQTT消息处理器和适配器,以及如何发送和接收MQTT消息。希望这篇文章能够帮助你快速入门MQTT和Spring Boot集成。 ### 回答2: 前言 MQTT是一种轻量级的机器与机器(M2M)通信协议,它可以在不同的设备和应用程序之间提供可靠的、基于发布/订阅模式的消息通信。在这篇文章中,我们将介绍如何使用Spring Boot集成MQTT,然后演示一下如何使用这种技术来构建一个简单的M2M应用程序。 集成MQTT 为了使用MQTT,在你的Spring Boot应用程序中添加以下依赖项: ``` <dependency> <groupId>org.eclipse.paho</groupId> <artifactId>org.eclipse.paho.client.mqttv3</artifactId> <version>1.2.0</version> </dependency> ``` 它将引入一个名为 org.eclipse.paho.client.mqttv3 的库,它提供了用于连接到MQTT代理服务器的客户端API。 现在,将MQTT连接信息描述在Spring Boot应用程序的 properties 文件中: ``` mqtt.host=tcp://localhost:1883 mqtt.username= mqtt.password= ``` MQTT的主机和端口信息在这里指定。在这个例子中,它连接到本地的MQTT代理服务器,端口1883。如果需要用户名和密码验证,需要在这栏中输入。 实现MQTT服务 要实现一个简单的MQTT客户端,需要创建一个名为MqttConfig的文件来更好地组织以下代码: ``` @Configuration @EnableConfigurationProperties(MqttProperties.class) public class MqttConfig { @Bean public MqttConnectOptions getMqttConnectOptions(MqttProperties mqttProperties) { MqttConnectOptions options = new MqttConnectOptions(); options.setCleanSession(true); options.setConnectionTimeout(mqttProperties.getConnectionTimeout()); options.setAutomaticReconnect(true); if (StringUtils.hasText(mqttProperties.getUsername())) { options.setUserName(mqttProperties.getUsername()); } if (StringUtils.hasText(mqttProperties.getPassword())) { options.setPassword(mqttProperties.getPassword().toCharArray()); } return options; } @Bean public MqttClient getMqttClient(MqttProperties mqttProperties, MqttConnectOptions options) throws MqttException { MqttClient client = new MqttClient(mqttProperties.getHost(), MqttClient.generateClientId()); client.connect(options); client.setCallback(new MqttCallback() { @Override public void connectionLost(Throwable throwable) { log.error("MQTT connection lost: " + throwable.getMessage()); } @Override public void messageArrived(String topic, MqttMessage message) throws Exception { } @Override public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { } }); return client; } } ``` 在这个类中,创建两个bean,getMqttConnectOptions 和 getMqttClient。getMqttConnectOptions方法返回一个MqttConnectOptions实例,它用于设置MQTT客户端的连接选项。主要用于设置此次会话是否需要清除,设置连接超时时间,是否自动重新连接等等。 getMqttClient 方法返回一个MqttClient实例,并使用MqttConnectOptions实例作为参数,连接到MQTT代理服务器,并设置回调函数。 实现发布/订阅 现在,创建一个名为 MqttPublishSubscribeConfig 的文件来订阅/发布消息: ``` @Configuration public class MqttPublishSubscribeConfig { private MqttClient mqttClient; public MqttPublishSubscribeConfig(MqttClient mqttClient) { this.mqttClient = mqttClient; } @Bean public MqttSubscribeBean mqttSubscribeBean() throws MqttException { return new MqttSubscribeBean(mqttClient); } @Bean public MqttPublishBean getMqttPublishBean() { return new MqttPublishBean(mqttClient); } } ``` 在这个配置类中,创建两个bean,MqttSubscribeBean 和 MqttPublishBean,分别用于订阅和发布消息。MqttSubscribeBean使用MqttClient进行订阅消息的相关操作,MqttPublishBean用于发布消息。 发布消息: ``` /** * 发布一个简单的MQTT消息 */ public void publish(String topic, String message) throws MqttException, UnsupportedEncodingException { mqttClient.publish(topic, message.getBytes("UTF-8"), 0, false); } ``` 订阅消息: ``` /** * 订阅一个简单的MQTT消息 */ public void subscribe(String topic) throws MqttException, UnsupportedEncodingException { mqttClient.subscribe(topic, 0); } ``` 测试 现在启动应用程序并访问 /index 时,将订阅名为 MyTopic 的MQTT主题,并在浏览器交互界面中发布一条新的消息。输出将包含上一条消息,并输出到控制台。 完整代码 最后,给出完整的Spring Boot集成MQTT的代码。为了简化代码和依赖,我们把发布/订阅方法移动到了主函数中。 MainClass: ``` @SpringBootApplication @ConfigurationProperties(prefix = "mqtt") public class SpringbootMqttApplication implements CommandLineRunner { private static final Logger log = LoggerFactory.getLogger(SpringbootMqttApplication.class); @Autowired private MqttClient mqttClient; private String host; private String username; private String password; // setter/getter.. @Override public void run(String... args) throws Exception { mqttClient.subscribe("MyTopic"); while (true) { String message = "Current Time: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); mqttClient.publish("MyTopic", message.getBytes(), 0, false); TimeUnit.SECONDS.sleep(10); } } public static void main(String[] args) { SpringApplication.run(SpringbootMqttApplication.class, args); } } ``` MqttConfig: ``` @Configuration @EnableConfigurationProperties(MqttProperties.class) public class MqttConfig { @Bean public MqttConnectOptions getMqttConnectOptions(MqttProperties mqttProperties) { MqttConnectOptions options = new MqttConnectOptions(); options.setCleanSession(true); options.setConnectionTimeout(mqttProperties.getConnectionTimeout()); options.setAutomaticReconnect(true); if (StringUtils.hasText(mqttProperties.getUsername())) { options.setUserName(mqttProperties.getUsername()); } if (StringUtils.hasText(mqttProperties.getPassword())) { options.setPassword(mqttProperties.getPassword().toCharArray()); } return options; } @Bean public MqttClient getMqttClient(MqttProperties mqttProperties, MqttConnectOptions options) throws MqttException { MqttClient client = new MqttClient(mqttProperties.getHost(), MqttClient.generateClientId()); client.connect(options); client.setCallback(new MqttCallback() { @Override public void connectionLost(Throwable throwable) { log.error("MQTT connection lost: " + throwable.getMessage()); } @Override public void messageArrived(String topic, MqttMessage message) throws Exception { log.info("Received Message: {}", new String(message.getPayload())); } @Override public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) { } }); return client; } } ``` MqttProperties: ``` @ConfigurationProperties(prefix = "mqtt") public class MqttProperties { private String host; private String username; private String password; private int connectionTimeout = 10; // setter/getter.. } ``` MqttPublishBean: ``` public class MqttPublishBean { private MqttClient mqttClient; public MqttPublishBean(MqttClient mqttClient) { this.mqttClient = mqttClient; } /** * 发布一个简单的MQTT消息 */ public void publish(String topic, String message) throws MqttException, UnsupportedEncodingException { mqttClient.publish(topic, message.getBytes("UTF-8"), 0, false); } } ``` MqttSubscribeBean: ``` public class MqttSubscribeBean { private MqttClient mqttClient; public MqttSubscribeBean(MqttClient mqttClient) { this.mqttClient = mqttClient; } /** * 订阅一个简单的MQTT消息 */ public void subscribe(String topic) throws MqttException, UnsupportedEncodingException { mqttClient.subscribe(topic, 0); } } ``` 参考链接: - https://github.com/eclipse/paho.mqtt.java - https://www.baeldung.com/java-mqtt-client-to-connect-broker ### 回答3: Spring Boot是一种流行的Java框架,它允许开发人员轻松创建、配置和部署可扩展的Web应用程序。MQTT是一种轻量级发布/订阅消息传递协议,适用于连接低带宽和不稳定网络的设备。本文将介绍如何在Spring Boot应用程序中使用Eclipse Paho MQTT客户端库集成MQTT。我们将建立一个简单的Spring Boot应用程序,该应用程序使用MQTT发布和订阅主题消息。 首先,需要添加Eclipse Paho MQTT客户端库的Maven依赖项,可以采用以下方式: ``` <dependency> <groupId>org.eclipse.paho</groupId> <artifactId>org.eclipse.paho.client.mqttv3</artifactId> <version>1.2.5</version> </dependency> ``` 接下来,我们需要定义一个MQTT配置类,该类负责建立MQTT客户端连接并设置连接选项。以下是一个简单的示例MQTT配置类: ``` @Configuration public class MqttConfig { private static final String MQTT_BROKER_URL = "tcp://localhost:1883"; private static final String MQTT_CLIENT_ID = "mqtt-test-client"; private static final int MQTT_KEEP_ALIVE_INTERVAL = 30; @Bean public MqttConnectOptions mqttConnectOptions() { MqttConnectOptions mqttConnectOptions = new MqttConnectOptions(); mqttConnectOptions.setCleanSession(true); mqttConnectOptions.setUserName("admin"); mqttConnectOptions.setPassword("password".toCharArray()); mqttConnectOptions.setConnectionTimeout(60); mqttConnectOptions.setKeepAliveInterval(MQTT_KEEP_ALIVE_INTERVAL); return mqttConnectOptions; } @Bean public MqttClient mqttClient() throws MqttException { MqttClient mqttClient = new MqttClient(MQTT_BROKER_URL, MQTT_CLIENT_ID); mqttClient.connect(mqttConnectOptions()); return mqttClient; } } ``` 在上面的代码中,我们定义了MQTT协议的一些基本参数,包括MQTT服务器的URL地址、客户端ID、保持连接的时间等,并将这些参数加载为Bean,并提供一个MQTT客户端的实例。 接下来,我们需要定义一个Controller类,该类将负责处理来自Spring Boot应用程序的HTTP请求,并使用MQTT发布和订阅消息。以下是一个简单的Controller类: ``` @RestController public class MqttController { private final MqttClient mqttClient; @Autowired public MqttController(MqttClient mqttClient) { this.mqttClient = mqttClient; } @PostMapping(value = "/mqtt/publish") public ResponseEntity<String> publish(@RequestBody MqttMessageRequest mqttMessageRequest) throws MqttException { String topic = mqttMessageRequest.getTopic(); String message = mqttMessageRequest.getMessage(); MqttMessage mqttMessage = new MqttMessage(message.getBytes()); mqttMessage.setQos(2); mqttClient.publish(topic, mqttMessage); return ResponseEntity.status(HttpStatus.OK).body("Message published successfully!"); } @GetMapping(value = "/mqtt/subscribe") public ResponseEntity<String> subscribe(@RequestParam String topic) throws MqttException { mqttClient.subscribe(topic, 2); return ResponseEntity.status(HttpStatus.OK).body("Subscribed to topic successfully!"); } } ``` 在上面的代码中,我们定义了两个请求处理程序publish()和subscribe()方法,用于发布和订阅MQTT消息。使用@Autowired注解将MQTT客户端Bean注入到MqttController中,以便能够在Controller方法中使用它。 最后,我们需要定义一个测试类来测试我们的应用程序,以下是一个简单的测试类: ``` @SpringBootTest class SpringbootMqttDemoApplicationTests { @Test void contextLoads() throws MqttException { final String topic = "test-topic"; final String message = "Hello World!"; MqttClient mqttClient = new MqttClient("tcp://localhost:1883", "test-client"); mqttClient.connect(); MqttMessage mqttMessage = new MqttMessage(message.getBytes()); mqttMessage.setQos(2); mqttClient.publish(topic, mqttMessage); mqttClient.disconnect(); } } ``` 在上面的代码中,我们向指定的MQTT主题发布了一条消息,并验证它是否成功发送。 以上就是使用Spring Boot集成MQTT的基本过程,运用MQTT协议可以有效的提高对IOT物联网设备的支持,为开发人员提供了更灵活、更可扩展的Web应用程序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值