MQTT协议概述
MQTT概述
MQTT 是在上世纪 90 年代末由 IBM 的 Andy Stanford-Clark 博士和 Arcom(现 Eurotech)的 Arlen Nipper 开发,用于通过卫星网络监测石油管道。最初的 MQTT 3.1 版本非常轻量级和易于实现,适用于各种物联网设备。
MQTT 3.1.1 于 2014 年发布,是一个 OASIS 标准,其中包括一些微调,增强了其清晰性和互操作性。它能够在资源有限的网络上高效地传输消息,因此在物联网应用中广受欢迎。
然而,随着物联网行业的发展,应用的需求也在不断变化。为了适应这些新的需求,在 2019 年发布了 MQTT 5.0,其中加入了一些新功能。MQTT 5.0 也因此能够更好地满足现代物联网应用的复杂需求。
MQTT(Message Queuing Telemetry Transport)
是一种轻量级、基于发布-订阅模式的消息传输协议,适用于资源受限的设备和低带宽、高延迟或不稳定的网络环境。它在物联网应用中广受欢迎,能够实现传感器、执行器和其它设备之间的高效通信。而且也可以应用在网络直播互动、手机消息推送等行业场景。
MQTT协议的特点
- 轻量级:开销低、报文小
- 可靠:支持多种QoS等级、支持会话感知和持久连接,可在较差的网络环境下保证消息的可靠传递
- 安全:可提供TLS和SSL加密功能,提供认证授权机制
- 双向通信:基于发布-订阅模式,易于扩展
- 连续、有状态的会话:提供客户端与Broker之间保持状态会话能力,系统即使在断开连接后也能记住未传递的消息
- 适用于大规模物联网设备
- 丰富的语言支持
相关概念
MQTT Broker
:MQTT Broker
(代理)是负责处理客户端请求的关键组件,包括建立连接、断开连接、订阅和取消订阅等操作,同时还负责消息的转发。Topic
:MQTT
根据Topic
来转发消息,用/
区分层级,支持通配符QoS
:MQTT
支持三种QoS
服务质量,详细请参考MQTT QoS介绍QoS-0
:消息最多传送一次。如果当前客户端不可用,它将丢失这条消息。QoS-1
:消息至少被传送一次。(适用于幂等操作)QoS-2
:消息只传送一次
工作流程
MQTT 连接由客户端向服务器端发起。任何运行了 MQTT 客户端库的程序或设备都是一个 客户端
,而 MQTT服务器
则负责接收客户端发起的连接,并将客户端发送的消息转发到另外一些符合条件的客户端。
客户端与服务器建立网络连接后,需要先发送一个 CONNECT
数据包给服务器。服务器收到 CONNECT
包后会回复一个 CONNACK
给客户端,客户端收到 CONNACK
包后表示 MQTT 连接建立成功。如果客户端在超时时间内未收到服务器的 CONNACK
数据包,就会主动关闭连接。
MQTT
主要基于TCP/IP
进行通信,但也支持通过WebSocket和UDP等进行网络传输。 使用MQTT over websocket
可以在浏览器中使用MQTT
(因为浏览器交互主要基于HTTP
,无法使用TCP
)
MQTT
借助发布/订阅模式来实现通信,将发送消息的客户端(发布者)与接收消息的客户端(订阅者)解耦,使得两者不需要建立直接的联系也不需要知道对方的存在。
- 客户端使用 TCP/IP 协议与 Broker 建立连接
- 客户端既向特定主题发布消息/订阅主题以接收消息
- MQTT Broker 接收发布的消息,转发给订阅了该主题的客户端
为什么用MQTT
MQTT
VS HTTP
HTTP
报文长,需要占用更多的网络开销HTTP
属于无状态协议,服务器不会记录客户端的状态,无法实现从连接异常断开时恢复未发送数据HTTP
需要轮训才能获取数据更新
MQTT 5.0
之前发布者无法得知订阅者是否受到了消息,或者正确处理了消息,所以MQTT 5.0
增加了请求响应
MQTT
VS 消息队列
尽管两者的特性比较相近,但他们的应用场景是有着显著不同的:
- 消息队列作为一种中间件,主要用于服务端应用之间的消息存储与转发,数据量大但客户端数量少。
- MQTT是一种消息传输协议,主要用于物联网设备间的消息传递,特点是连接的设备量很大。
有时MQTT
和消息队列会一起使用,MQTT
专注于处理物联网设备上报的数据,然后消息队列订阅这些消息并转发到不同的业务系统进行处理。
而且相比消息队列,MQTT
的主题不需要提前创建,在订阅或发布时即自动的创建了主题,开发者无需再关心主题的创建,并且也不需要手动删除主题。
MQTT保留消息
发布订阅模式虽然能让消息的发布者与订阅者充分解耦,但也订阅者无法主动向发布者请求消息。因此借助保留消息,新的订阅者可以立即获得最近的状态。
发布者发布消息时,如果Retained
标记被设置为 true
,则该消息即是 MQTT
中的保留消息(Retained Message
)。MQTT 服务器会为每个主题存储最新一条保留消息,以方便消息发布后才上线的客户端在订阅主题时仍可以接收到该消息。当客户端订阅主题时,如果服务端存在该主题匹配的保留消息,则该保留消息将被立即发送给该客户端。
保留消息的使用场景如下:
- 设备状态发生变更的时候才会上报,但控制端需要在上线后就马上获取当前状态
- 传感器上报数据周期长,订阅者需要立即获取到最新的数据。
- 传感器的一些固定属性可以上线后发布一条保留消息来告知后续订阅者
MQTT遗嘱消息
遗嘱消息(Will Message
or Last Will and Testament
)是MQTT
中的一个重要功能,它解决了只有服务端才能知道客户端是否在线的问题,使我们能够为意外离线的客户端优雅地完成善后事宜。在 MQTT
中,客户端可以在连接时在服务端中注册一个遗嘱消息,与普通消息类似,我们可以设置遗嘱消息的主题、有效载荷等等。当该客户端意外断开连接,服务端就会向其他订阅了相应主题的客户端发送此遗嘱消息。这些接收者也因此可以及时地采取行动,例如向用户发送通知、切换备用设备等等。
遗嘱消息原理
客户端在连接时指定遗嘱消息
遗嘱消息在客户端发起连接时指定,它和 Client ID、Clean Start 这些字段一起包含在客户端发送的 CONNECT 报文中。与普通消息一样,我们可以为遗嘱消息设置主题(Will Topic)、保留消息标识位(Will Retain)、属性(Will Properties)、QoS(Will QoS)和有效载荷(Will Payload)
客户端意外关闭时服务端发布遗嘱消息
如果客户端在连接时指定了遗嘱消息,那么服务端就会将该遗嘱消息存储在相应的会话中,直到以下任一条件满足时发布它:
- 服务端检测到了一个
I/O
错误或者网络故障 - 客户端在
Keep Alive
时间内未能通讯 - 客户端在没有发送
Reason Code
为0x00
(正常关闭)的DISCONNECT
报文的情况下关闭了网络连接 - 服务端在没有收到
Reason Code
为0x00
(正常关闭)的DISCONNECT
报文的情况下关闭了网络连接,例如客户端的报文或行为不符合协议要求而被服务端关闭连接。
总结以下就是客户端在服务端没有收到 Reason Code
为 0x00
的 DISCONNECT
报文的情况下关闭,发送遗嘱消息,客户端正常发送 Reason Code
为 0x00
的 DISCONNECT
报文后关闭,不会发布遗嘱消息。
MQTT 5.0 延迟发布特性
如果网络连接中断只是暂时的,那么遗嘱消息被发送是无意义的,因此MQTT 5.0
增加了Will Delay Interval
属性,来决定服务端在网络连接关闭后延迟多久发布遗嘱消息。
配合保留消息使用
配合保留消息使用:正常情况下服务端一旦发布了遗嘱消息,就会将它从会话中删除,但如果关心该遗嘱消息的客户端不在线,就会错过该遗嘱消息,所以可以把遗嘱消息设置为保留消息。
MQTT 5.0
MQTT 5.0 新功能如下:
- 原因代码:了解断开连接或失败原因
- 会话过期间隔:管理会话的生命周期
- 主题别名:减少消息头部的开销
- 用户属性:MQTT 头部中的自定义元数据
- 订阅选项:细粒度的订阅控制
- 请求/响应:允许客户端回复指定主题
- 共享订阅:订阅者负载均衡功能
参考: