Android 消息队列之MQTT的使用:物联网通讯,HTTP太重了,使用MQTT;订阅、发送数据和接受数据、会话+消息过期机制,实现双向通讯。

目录

一、前言

  1. HTTP协议在物联网场景的局限性
  2. 切换MQTT的背景原因

二、MQTT协议基础

  1. 协议定义与特点
  2. 核心优势
    • 实时通讯能力
    • 低开销特性
    • 高可靠性保障
    • 连接数优

三、实际应用场景

  1. 室内温湿度数据上传
  2. 设备远程控制
  3. 批量控制实现

四、会话管理、消息过期设置

4.1 会话管理

  1. Clean Session参数
    • 新旧会话模式对比
    • 典型应用场景

4.2 消息过期设置

  1. MQTT 5.0消息过期机制
    • Message Expiry Interval属性
    • QoS级别影响

一、前言

在开发的时候,我们一般都使用Http和后台进行通讯,比如我们是开发物联网的,设备会有很多数据需要频繁发给后台,使用Http来做这件事情,就感觉很重,比如会遇到如下这些问题:

  1. 开发成本:需要后台创建接口,前台去请求。
  2. 连接数过多:在HTTP协议中,每次请求都需要建立一个新的连接,这可能导致连接数过多,特别是在高并发场景下。对于自动售卖机来说,如果同时有大量的用户进行交互,可能会导致服务器资源紧张,影响性能。
  3. 开销较大:HTTP协议的消息头部相对复杂,包含了大量的元数据,这增加了网络传输的开销。
  4. 实时性较差:HTTP协议是基于请求-响应模式的,需要客户端主动发起请求才能获取数据。这导致在实时性要求较高的场景下,HTTP可能无法满足需求。也就是服务器不能主动发数据给客户端。

基于这样的背景,我们选择切换成MQTT


二、是什么

MQTT(Message Queuing Telemetry Transport)是一个轻量级的发布/订阅消息协议,它构建于TCP/IP协议之上,为小型设备提供了稳定的网络通讯。MQTT协议设计简单,易于实现,非常适合在物联网(IoT)和移动应用中使用。

你会发现传递的数据大小是根据你的内容来决定。

能干嘛?

1、实时通讯:MQTT支持异步通讯模式,客户端可以通过订阅主题来接收感兴趣的消息,而不需要主动请求。这使得MQTT非常适合实时通讯和事件驱动的应用场景。

2、低开销:MQTT协议的数据包开销非常小,消息头部仅需2字节,非常适合网络带宽受限或设备资源受限的环境。

3、高可靠性:MQTT支持三种不同的服务质量(QoS)级别,可以根据实际需求选择合适的级别来确保消息的可靠传输。同时,MQTT还具有自动重连机制,能够在网络断开时自动恢复连接。

4、减少连接数:与HTTP相比,MQTT协议只需要客户端与服务器(Broker)建立一次连接就可以进行多次消息发布和订阅,大大减少了网络连接次数和数据传输量。


三、实际应用场景

3.1 室内温湿度数据上传

应该如何设计呢?比如我现在有十台设备,数据都要上传到后台服务器:

  1. 主题:比如你温湿度数据发送到哪个主题,后台服务器这边就会订阅这个主题,
  2. 数据:数据里面需要保护设备的唯一号,这样服务器才知道是哪台设备发上来的。
bash 复制代码
# 设备端:每隔30秒发布数据
client.publish("envmon/D001/sensor", json.dumps(data), qos=1)

# 服务端:订阅所有设备的传感器主题,使用通配符
mosquitto_sub -t "envmon/+/sensor" -v

3.2 后台服务器重启温湿度器

比如有时候,想远程在移动端或web端,关掉温湿度器,那么应该如何设计呢?

  1. 主题:客户端这边订阅指定的主题,一般是以设备唯一号作为主题,后台会往这个主题里面发送消息。这样就能精准的发送到指定的设备上去。
  2. 数据:数据格式,{功能码:开关码}。因为可能会有很多远程功能,所以我们需要设计功能码。
java 复制代码
服务端:
client.publish("envmon/D001/control", xxx, qos=2)

客户端:
client.subscribe("envmon/D001/control", qos=2)

3.2 如果我想实现批量重启呢?或者批量关闭温湿度器呢?

客户端可以订阅多个主题,通过多次调用 subscribe() 方法实现多主题订阅。

scss 复制代码
// 订阅温湿度数据主题
subscribe("envmon/D001/sensor", 1);
subscribe("envmon/D002/sensor", 1);

// 订阅设备控制主题
subscribe("envmon/D001/control", 2);
subscribe("envmon/D002/control", 2);

这里,我们要实现的批量,可以使用通配符

  1. 客户端
java 复制代码
// 订阅所有设备的传感器数据(envmon/任何设备ID/sensor)
subscribe("envmon/+/sensor", 1); 
  1. 服务端:发送所有设备就都能收到。
bash 复制代码
envmon/D001/sensor

如果说,要分组,或者勾选,也可以订阅单条的来进行发送。

四、会话、消息过期设置

4.1 会话

会话,指的是MQTT客户端与MQTT服务端之间的连接。

会话一般可以设置两个参数

  1. 每次打开是否是一个全新的会话,还是延续上一次的会话。
  2. 会话的状态会维持多久。

参数一:是否延续会话(Clean Session)​

​两种模式对比​
场景 Clean Session=true(新会话) Clean Session=false(延续会话)
设备断网后重连 丢失所有订阅和未读消息 自动恢复订阅列表和离线期间消息
适用设备 临时设备(如一次性传感器) 重要设备(如智能门锁)
服务器资源消耗 高(需存储消息)
典型代码场景 setCleanSession(true) setCleanSession(false)

实际案例:​

智能门锁(Clean Session=false):

  1. 门锁断网时,用户通过APP发送开锁指令
  2. 服务器将指令暂存在「会话快递柜」
  3. 门锁网络恢复后,立即收到开锁指令

​参数二:会话有效期(Session Expiry)​

​设置方式​
scss 复制代码
// 设置会话保留时间为1小时(单位:秒)
options.setSessionExpiryInterval(3600); 
​关键行为规则​
有效期设置 服务器行为
0 关闭连接立即销毁会话(等同 Clean Session=true)
3600(1小时) 设备离线后,会话保留1小时,超时后自动清除
0xFFFFFFFF 永久保留会话(慎用!会导致服务器内存泄漏)

也就是,即使Clean Session=false(延续会话),会话有效期设置为60秒,如果离线超过60秒,那么也会清空之前的消息。

4.2 消息过期设置

MQTT 5.0 协议新增了 ​Message Expiry Interval​ 属性,可直接设置消息过期时间。

java 复制代码
import org.eclipse.paho.mqttv5.common.MqttMessage;
import org.eclipse.paho.mqttv5.common.packet.MqttProperties;

// 创建消息并设置过期时间为60秒
MqttMessage message = new MqttMessage();
message.setPayload("Hello".getBytes());
message.setQos(1);

// MQTT 5.0 属性设置
MqttProperties properties = new MqttProperties();
properties.setMessageExpiryInterval(60L); // 单位:秒
message.setProperties(properties);

// 发布消息
client.publish("topic/commands", message);
2. 服务器行为(需支持MQTT5.0)
  • 消息在服务器存储超过设定时间后自动删除
  • 过期消息不会转发给订阅者
  • QoS 2 消息在过期前会完成确认流程
相关推荐
浩宇软件开发14 分钟前
Android开发,实现一个简约又好看的登录页
android·java·android studio·android开发
未扬帆的小船28 分钟前
在gpt的帮助下安装chales的证书,用于https在root情况下抓包
android·charles
万户猴31 分钟前
【 Android蓝牙-十】Android各版本蓝牙行为变化与兼容性指南
android·蓝牙
张风捷特烈2 小时前
FFmpeg 7.1.1 | 调试 ffmpeg.c 环境 - Widows&Clion&WSL
android·ffmpeg
努力努力再努力wz2 小时前
【Linux实践系列】:进程间通信:万字详解命名管道实现通信
android·linux·运维·服务器·c++·c
百锦再3 小时前
Android Studio 中使用 SQLite 数据库开发完整指南(Kotlin版本)
android·xml·学习·sqlite·kotlin·android studio·数据库开发
Gerry_Liang3 小时前
Java基础361问第16问——枚举为什么导致空指针?
android·java·开发语言
RichardLai884 小时前
[Flutter 基础] - Flutter基础组件 - Image
android·flutter
一杯凉白开4 小时前
虽然我私生活很混乱,但是我码德很好-多线程竞态条件bug寻找之旅
android
科昂4 小时前
Dart 异步编程:轻松掌握 Future 的核心用法
android·flutter·dart