白话消息队列遥测传输协议(MQTT)
MQTT 是一种基于发布/订阅模式的轻量级通讯协议,由 IBM 在 1999 年发布,构建于 TCP/IP 协议之上。它是一种开放的消息协议,简单易用,支持消息的 Qos(服务质量)。MQTT 的最大优势在于可以以极少的代码和带宽为连接远程设备提供实时、可靠的消息服务。这些特性使得它在物联网、小型设备、移动应用、车联网、电力能源等领域得到了广泛应用。
在学习嵌入式系统时,我了解到 MQTT 协议。嵌入式系统中还有一种类似的协议叫 CoAP,不过今天我们主要讨论 MQTT。
MQTT 的由来
MQTT 协议由 Andy Standford-Clark 博士和 Arlen Nipper 博士于 1999 年发明,最初设计用于在网络带宽狭窄和电力消耗极低的情况下,为石油管道传感器和人造卫星之间提供一种轻量、可靠的二进制通讯协议。2011 年,IBM 和 Eurotech 将 MQTT 协议捐赠给 Eclipse 基金会,并加入了 Eclipse M2M Industry 工作组织。2014 年 10 月,MQTT 正式成为 OASIS 国际标准。
这让我思考:如果 MQTT 没有公开,不就是一个私有协议吗?还能有这么大的影响力吗?学习 TCP/IP 时,我也有类似的问题:TCP 连接后可以发送数据,但数据格式还需要自己定义,发送方和接收方都需遵循相同的格式。此外,TCP 连接如何认证?是否仅依靠 IP 白名单?在研究 MQTT 规范后,我找到了这些问题的答案。
MQTT 的特点
- 轻量可靠:MQTT 报文格式简洁,在受限的硬件设备和低带宽、高延迟的网络环境中,能够实现稳定传输。
- 发布/订阅模式:解耦发布者与订阅者,允许异步通信,即订阅者和发布者无需直接连接或同时在线。
- 为物联网而生:提供心跳机制、遗嘱消息、Qos 服务质量等级和离线消息等特性,符合物联网应用需求。
- 生态完善:支持多语言客户端和 SDK,众多云厂商和嵌入式硬件都提供支持。
轻量可靠是如何实现的?
MQTT 基于 TCP/IP 协议,TCP/IP 是一种面向连接的可靠通信协议。我主要研究的是 MQTT 3.1.1 协议,它定义了 14 种控制包,应用之间的交互通过这些控制包协作完成。每个控制包由 固定包头、可变包头 和 载荷 组成。
固定包头
固定包头的大小为 2 字节。第一个字节的高四位表示控制包类型,低四位为包类型的特殊标识。第二个字节表示控制包的剩余字节长度,采用变长编码方式表示。
例如,将十进制 321 进行编码:首先,321 除以 128 得余数 65,商 2,将 65 存在第一个字节。由于商不为 0,表示还有下一个字节,因此第一个字节的第 8 位需要置 1。接着,将商 2 继续除以 128,结果为 2,存储在第二个字节。解码时,通过对字节进行位运算,可以还原出 321。
可变包头
可变包头并非所有控制包都包含,它通常用于订阅、发布等特定包。可变包头包含控制数据,例如 2 字节的包标识符,用于唯一标识控制包。
载荷
载荷用于存放应用消息,仅在部分控制包中存在。载荷包含用户提交的实际数据。
认证与连接
在 TCP 连接建立后,客户端会发送 CONNECT 控制包。CONNECT 包中包含连接标识、用户名、密码等信息,客户端通过该包完成身份认证。如果第一个包不是 CONNECT 控制包,服务器将断开连接。
Qos(服务质量)
MQTT 支持 3 种 Qos 等级:
- Qos 0:最多分发一次,消息发送后不保证接收者是否收到。
- Qos 1:最少分发一次,消息至少会被接收一次,接收方需要回复 PUBACK 确认消息已收到。
- Qos 2:精确分发一次,确保消息不会丢失或重复,需通过 PUBREC 和 PUBREL 进行确认。
Qos2 的实现机制较为复杂,但它确保了消息在通信双方之间的唯一性和正确传递。
发布/订阅模式
MQTT 使用发布/订阅模式,发布者与订阅者通过主题进行解耦。发布者将消息发送至主题,订阅者订阅该主题以接收消息。这种机制允许多个硬件和软件厂商间的协作。
遗嘱消息
遗嘱消息用于监控设备的异常断开。发布者在连接时可以指定遗嘱消息,当客户端异常断开时,Broker 将遗嘱消息分发给订阅了该主题的客户端。
心跳包
MQTT 使用心跳包来保持连接,避免依赖 TCP 的长时间心跳机制。
总结
MQTT 是一种轻量、可靠的通信协议,特别适合物联网等资源受限的场景。它通过灵活的发布/订阅模式、Qos 机制和认证方式,为嵌入式设备、移动应用和物联网应用提供了良好的通信解决方案。
更多细节请参考官方文档:MQTT 3.1.1 规范。