首页 > 编程开发 > MQTT 协议入门
2024
10-23

MQTT 协议入门

MQTT(Message Queuing Telemetry Transport)是一种轻量级、基于发布-订阅模式的消息传输协议,适用于资源受限的设备和低带宽、高延迟或不稳定的网络环境。它在物联网应用中广受欢迎,能够实现传感器、执行器和其它设备之间的高效通信。

1 MQTT 协议的主要特性

  • 轻量级:开销低,报文小;
  • 可靠:支持多种 QoS 等级、会话感知和持久连接;
  • 安全通信:支持 TLS 和 SSL 以及用户名/密码或客户端证书验证;
  • 双向通信:MQTT 协议采用发布-订阅机制,同一个客户端既可以作为消息发布者,也可以作为消息订阅者;
  • 连续、有状态的会话:提供了客户端与 Broker 之间的保活机制;
  • 大规模物联网设备支持;
  • 多语言支持:支持在 Golang、Python、PHP、JavaScript 等多种编程语言中使用。

2 MQTT 的工作原理

MQTT 协议采用发布-订阅模式,消息的发布者和订阅者之间无需直接建立连接,而是通过 MQTT Broker 来进行消息的路由和分发。

MQTT 的一般工作流程如下:

  1. 客户端使用 TCP/IP 协议与 Broker 建立连接;
  2. 客户端既可以向特定主题发布消息,也可以订阅主题以接收消息。
  3. MQTT Broker 接收发布的消息,并将这些消息转发给订阅了对应主题的客户端。

下图展示了一个示例,传感器 Client 1 作为消息发布者,将采集到的温度发布给了 Broker,各类终端(Client 2、Client 3、Client 4)订阅了 Temperature 主题,Broker 接收到 Client 1 发送的消息后,会将其转发给订阅了 Temperature 主题的终端。

MQTT 协议入门 - 第1张  | Weiguang的博客

MQTT 协议根据主题来转发消息,主题通过 /来区分层级,类似于 URL 路径:

sensor/10/temperature
sensor/8/weight

MQTT 主题支持以下两种通配符:+#

  • +:表示单层通配符,例如 a/+ 匹配 a/xa/y
  • #:表示多层通配符,例如 a/# 匹配 a/xa/b/c/d

注意:通配符主题只能用于订阅,不能用于发布。

MQTT 提供了三种服务质量(QoS),在不同网络环境下保证消息的可靠性。

  • QoS 0:消息最多传送一次。如果当前客户端不可用,它将丢失这条消息。
  • QoS 1:消息至少传送一次。
  • QoS 2:消息只传送一次。

3 MQTT 快速上手

可以参考这篇博客 EMQX 快速上手

4 MQTT 协议功能演示

4.1 保留消息

当 MQTT 客户端向服务器发布消息时,可以设置保留消息标志。保留消息存储在消息服务器上,后续订阅该主题的客户端仍然可以收到该消息。

如下图所示,我们在 emqx_publisher1 上勾选 Retain 选项,然后向 test/lwg 主题发送两条消息 1 和 2。

MQTT 协议入门 - 第2张  | Weiguang的博客

然后让 emqx_subscriber1 连接 Broker,可以看到只收到了第二条消息,这说明服务器只会为主题保留最近的一条保留消息。

MQTT 协议入门 - 第3张  | Weiguang的博客

4.2 Clean Session

MQTT 客户端通常只能在在线状态下接收其它客户端发布的消息。如果客户端离线后重新上线,它将无法收到离线期间的消息。

但是,如果客户端连接时设置 Clean Session 为 false,并且使用相同的客户端 ID 再次上线,那么消息服务器将为客户端缓存一定数量的离线消息,并在它重新上线时发送给它。

创建一个名为 MQTTv3 的连接,设置 Clean Session 为 false,选择 MQTT 版本为 3.1.1。连接成功后,订阅 clean_session_false 主题,并将 QoS 设置为 1。订阅成功后,断开连接。

然后,创建一个名为 MQTTv3_Publish 的连接,MQTT 版本也设置为 3.1.1。连接成功后,向 clean_session_false 主题发布三条消息。

MQTT 协议入门 - 第4张  | Weiguang的博客

接着,选择 MQTTv3 连接,点击连接按钮重新连接到服务器,会收到三条离线消息。

MQTT 协议入门 - 第5张  | Weiguang的博客

4.3 遗嘱消息

MQTT 客户端在向服务器发起 CONNECT 请求时,可以选择是否发送遗嘱消息标志,并指定遗嘱消息的主题和有效载荷。

如果 MQTT 客户端异常离线(在断开连接前没有向服务器发送 DISCONNECT 消息),MQTT 服务器会发布遗嘱消息。

我们创建一个名为 Last_Will 的连接来演示这个功能。

  • 为了快速看到效果,我们把 Keep Alive 设置为 5 秒。
  • Last-Will Topic 设置为 last_will
  • Last-Will QoS 设置为 1
  • Last-Will Retain 设置为 true
  • Last-Will Payload 设置为 offline

MQTT 协议入门 - 第6张  | Weiguang的博客

连接成功后,我们断开电脑网络超过 5 秒(模拟客户端异常断开连接),然后再恢复网络。

接着启动 Simple_Demo 连接,并订阅 last_will 主题。将会收到 Last_Will 连接设置的遗嘱消息。

MQTT 协议入门 - 第7张  | Weiguang的博客

5 MQTT 协议连接参数设置

5.1 连接地址

MQTT 协议可基于 TCP、UDP、WebSocket等协议进行网络传输,基于 TCP 和 WebSocket 的连接地址如下:

# 基于 TCP,不加密,端口号一般为 1883
mqtt://broker.emqx.io:1883

# 基于 TLS/SSL 的 TCP,端口号一般为 8883
mqtts://broker.emqx.io:1883

# 基于普通的 WebSocket,端口号一般为8083
# 当使用 WebSocket 连接时,连接地址还需要包含 Path, EMQX 默认配置的 Path 是 /mqtt
ws://broker.emqx.io:8083/mqtt

# 基于 TLS/SSL 的 WebSocket,端口号一般为 8084
wss://broker.emqx.io:8083/mqtt

5.2 客户端 ID (Client ID)

MQTT 服务器使用 Client ID 识别客户端,Client ID 通常为 1 – 23 个字节的 UTF-8 字符串。

# 两个 Client ID 示例
mqttx_baa6aedd
python-mqtt-tcp-sub-692

5.3 用户名与密码(Username & Password)

如果不使用加密协议, MQTT 协议的用户名和密码将会明文传输,如果配置了认证信息,推荐使用 mqtts或者 wss协议。

可以在配置文件中修改以下配置,将 Broker 设置为匿名认证,这时用户名和密码设置为空即可。

allow_anonymous = true

5.4 连接超时时间(Connect Timeout)

连接超时时长,收到服务器连接确认前的等待时间,等待时间内未收到连接确认则为连接失败。

5.5 保活周期(Keep Alive)

保活周期是一个以秒为单位的时间间隔。客户端在无报文发送时,将按 Keep Alive 设定的值定时向服务端发送心跳报文,确保连接不被服务端断开。

在连接建立成功后,如果服务器没有在 Keep Alive 的 1.5 倍时间内收到来自客户端的任何包,则会认为和客户端之间的连接出现了问题,此时服务器

会断开和客户端的连接。

5.6 洁净会话(Clean Session)

false 时表示创建一个持久会话,在客户端断开连接时,会话仍然保持并保存离线消息,直到会话超时注销。为 true 时表示创建一个新的临时会话,在客户端断开时,会话自动销毁。

注意: 持久会话恢复的前提是客户端使用固定的 Client ID 再次连接,如果 Client ID 是动态的,那么连接成功后将会创建一个新的持久会话。

5.7 遗嘱消息(Last Will)

遗嘱消息是 MQTT 为那些可能出现意外断线的设备提供的将遗嘱优雅地发送给其他客户端的能力。设置了遗嘱消息消息的 MQTT 客户端异常下线时,MQTT 服务器会发布该客户端设置的遗嘱消息。

遗嘱消息可以看作是一个简化版的 MQTT 消息,它也包含 Topic、Payload、QoS、Retain 等信息。遗嘱消息将会发布到遗嘱 Topic,Payload 是遗嘱消息的内容,QoS 等级与普通 MQTT 消息的含义一致,遗嘱 Retain 为 true 时表明遗嘱消息是保留消息。

**意外断线包括***:因网络故障,连接被服务端关闭;设备意外掉电;设备尝试进行不被允许的操作而被服务端关闭连接等,不包括客户端主动断开连接。*

5.8 MQTT 5.0 新增的连接参数

目前使用较多的 MQTT 协议版本有 MQTT v3.1、MQTT v3.1.1 及 MQTT v5.0。MQTT 5.0 新增了一些连接参数,本节将进行介绍。

5.8.1 Clean Start & Session Expiry Interval

MQTT 5.0 中将 Clean Session 拆分成了 Clean Start 与 Session Expiry Interval。

  • Clean Start 用于指定连接时是创建一个全新的会话还是尝试复用一个已存在的会话。参数值为 true 时创建一个全新的会话,为 false 时尝试复用一个已经存在的会话。
  • Session Expiry Interval 用于指定网络连接断开后会话的过期时间。设置为 0 或未设置,表示断开连接时会话即到期;设置为大于 0 的数值,则表示会话在网络连接关闭后会保持多少秒;设置为 0xFFFFFFFF 表示会话永远不会过期。

5.8.2 MQTT 5.0 连接属性(Connect Properties)

5.8.2.1 能力协商

CONNECT 和 CONNACK 报文中新增的属性字段,主要是增强了客户端与 Broker 之间的协商能力。这些属性同时存在于 CONNECT 和 CONNACK 报文中,因此可以在连接过程中相互告知对方自己的处理能力,使对方能够按照自己的期望提供服务。

  • Maximum Packet Size:协商 Client 和 Broker 各自能够接受的最大报文长度;
  • Maximum QoS:Broker 告知 Client 自己能够支持的最大服务质量;
  • Session Expiry Interval:会话过期间隔;
  • Receive Maximum:接收最大值;
  • Topic Alias Maximum:主题别名最大值。
5.8.2.2 可选的服务端功能

考虑到不是所有 MQTT Broker 都是完整实现,可能无法提供完整的 MQTT 5.0 功能,因此 MQTT 5.0 还支持在 Broker 的CONNACK 报文中声明支持的功能。

  • Retain Available:是否支持保留消息;
  • Wildcard Subscription Available:是否支持通配符订阅;
  • Subscription Identifier Available:是否支持订阅标志服;
  • Shared Subscription Available:是否支持共享订阅。
5.8.2.3 自动分配 Client ID

只要 Client 在连接时提供一个零字节的 Client ID,Broker 会通过 CONNACK 报文中的 Assigned Client Identifier 属性为 Client 分配一个全局唯一的 Client ID,Client 可以一直持有和使用这个 Client ID,直到会话过期。

最后编辑:
作者:lwg0452
这个作者貌似有点懒,什么都没有留下。
捐 赠如果您觉得这篇文章有用处,请支持作者!鼓励作者写出更好更多的文章!

留下一个回复

你的email不会被公开。