MQTT 协议学习

前言

最近项目里采用了 MQTT 来做长连接,实现即时通信和 APP 推送的功能,特此总结记录下。

什么是 MQTT?

MQTT是一个轻量的、发布订阅模式的消息传输协议,专门针对低带宽和不稳定网络环境的物联网应用设计,它可以实现机器之间通信,在物联网方面有着巨大的优势,同时在app推送、即时通信也都有应用(我们公司就是在这两个场景上使用了 MQTT)。

MQTT官网: http://mqtt.org

MQTT V3.1.1协议规范: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html

MQTT 协议中文版: https://legacy.gitbook.com/book/mcxiaoke/mqtt-cn/discussions/11

MQTT 协议特点

  1. 简单的开放消息协议,开销很小。
  2. 基于 TCP/IP。
  3. 1字节固定报头,2字节心跳报文,报文结构紧凑。
  4. 基于发布订阅模式(可以理解为消息队列)。
  5. 三种消息 Qos 支持:0-最多一次,1-最少一次,2-只有一次。

MQTT和传统MQ对比

传统的消息中间件,例如RabbitMQ、Kafka 等都是面向微服务大数据等领域,负责消息的存储和转发,消息的生产者和消费者都是服务端应用。这种设计很适合服务端技术栈固定、语言平台固定的场景。而移动互联网和 IoT 领域则有所不同,这类场景更侧重于多语言多平台的海量设备接入,消息的生产和消费过程的业务属性很突出,传统的消息中间件并不适合这些领域。

MQTT 在设计上是一个面向移动互联网和 IoT 领域的无状态网关,只关心海量移动端设备的接入、管理和消息传输,消息数据的存储则都会路由给后端存储产品。

适用场景对比

适用场景
MQTT 面向移动端场景,移动端场景一般都具备海量设备,单设备数据较少的特点。因此,微消息队列 MQTT 适用于拥有大量在线客户端(很多企业设备端过万,甚至上百万),但每个客户端消息较少的场景。
消息队列 面向服务端的消息引擎,主要用于服务组件之间的解耦、异步通知、削峰填谷等,服务器规模较小(极少企业服务器规模过万),但需要大量的消息处理,吞吐量要求高。因此,消息队列 MQ 适用于服务端进行大批量的数据处理和分析的场景。

MQTT 的 Broker

Broker 是代理服务器,这里和消息队列的概念基本一样,生产者将消息发送至 Broker 中的 topic,消费者通过订阅 topic即可收到消息,MQTT 协议基于 Pub/Sub 模式。

市面上的 Broker 有很多,如 RabbitMQ 就支持 MQTT,还有支持百万连接的 EMQ 等。

MQTT 的 Topic

MQTT 基于主题(topic)进行消息路由,主题类似路径,如:

dev/push/1

dev/push/#

test/2/feed/comment

test/+/feed/comment

Topic 通过”/“分隔层级,支持”+”、”#”通配符:

“+”:表示通配一个层级,例如a/+,匹配a/x, a/y

“#”:表示通配多个层级,例如a/#,匹配a/x, a/b/c/d 。

注意:topic 可以就是 “#”,表示匹配所有 topic,”#”只能在末尾

注意:在 MQTT 协议中,消息发布(Pub)只能向特定名称Topic中发送消息,不支持匹配符。但是在订阅(Sub)时,支持通过通配符的方式订阅多个主题。”

MQTT V3.1.1协议报文

报文结构

固定报头(Fixed header) + 可变报头(Variable header) + 报文有效载荷(Payload)

报文类型

类型名称 类型值 报文说明
CONNECT 1 发起连接
CONNACK 2 连接回执
PUBLISH 3 发布消息
PUBACK 4 发布回执
PUBREC 5 QoS2消息回执
PUBREL 6 QoS2消息释放
PUBCOMP 7 QoS2消息完成
SUBSCRIBE 8 订阅主题
SUBACK 9 订阅回执
UNSUBSCRIBE 10 取消订阅
UNSUBACK 11 取消订阅回执
PINGREQ 12 PING请求
PINGRESP 13 PING响应
DISCONNECT 14 断开连接

心跳

客户端在无报文发送时,按保活周期 (KeepAlive) 定时向服务端发送 PINGREQ 心跳报文,服务端响应 PINGRESP 报文。PINGREQ/PINGRESP报文均 2 个字节,服务端在 1.5 个心跳周期内,既没有收到客户端发布订阅报文,也没有收到PINGREQ 心跳报文时,主动心跳超时断开客户端 TCP 连接。

QoS

QoS 等于0:消息最多发送一次。

QoS 等于1:消息最少发送一次。

QoS 等于2:消息正好发送一次。

MQTT 发布消息 QoS 保证不是端到端的,是客户端与服务器之间的。订阅者收到 MQTT 消息的 QoS 级别,最终取决于发布消息的 QoS 和主题订阅的 QoS,结果如下:

发布消息的QoS 主题订阅的QoS 接收消息的QoS
0 0 0
0 1 0
0 2 0
1 0 0
1 1 1
1 2 1
2 0 0
2 1 1
2 2 2

Clean Session

MQTT客户端向服务器发起CONNECT请求时,可以通过’Clean Session’标志设置会话。

Clean Session=0,表示创建一个持久会话,在客户端断开连接时,会话仍然保持并保存离线消息,直到会话超时注销。

Clean Session=1,表示创建一个新的临时会话,在客户端断开时,会话自动销毁。