为什么每份 Android 简历都说 “熟悉 MQTT 协议”?

2021-07-12  本文已影响0人  彭旭锐

点赞关注,不再迷路,你的支持对我意义重大!

🔥 Hi,我是丑丑。本文 GitHub · Android-NoteBook 已收录,这里有 Android 进阶成长路线笔记 & 博客,欢迎跟着彭丑丑一起成长。(联系方式在 GitHub)

前言


目录


1. 什么是 MQTT?

MQTT (Message Queuing Telemetry Transport,消息队列遥测传输) 是一种基于 TCP/IP 协议族的应用层协议。MQTT 协议是专门针对硬件性能低下 & 网络状况不稳定的场景设计的,这使得 MQTT 在物联网和移动应用等受限场景得到广泛应用。

1.1 MQTT 协议的发展历史

目前,MQTT 主要分为两个大版本:

1.2 MQTT 协议和 HTTP 协议有什么区别?

特性 MQTT 协议 HTTP 协议
传输层 TCP TCP 或 UDP
消息传递 发布 - 订阅模型 请求 - 响应模型
消息分发 1 对 0/1/N 1 对 1
数据安全 使用 SSL/TLS 不一定采用 HTTPS
加密 应用层对有效载荷加密 不在应用层加密
消息大小 较小 较大

1.3 为什么 MQTT 协议适合物联网和移动应用场景?

物联网和移动应用场景的特点是硬件性能低下和网络状况不稳定,而 MQTT 协议就是专门针对这种环境设计的,主要在四个方面有优势:

1.4 谁更适合物联网(HTTP/2 & WebSocket & MQTT)?

结论:这三种协议并没有绝对的优胜者,最好的协议取决于具体的需求和限制条件。但如果只从带宽、电池、功能多样性这些基本条件看,MQTT 在其中是更占优的选择。

1.5 为什么 MQTT 协议基于 TCP,可以基于 UDP 协议吗?

MQTT 协议的设计特性中包含了一项 “高可靠性交付”,它需要一个保证可靠的底层传输层协议,因此 TCP 协议、TLS 协议、WebSocket 协议都可以作为 MQTT 的底层协议。而无连接的 UDP 协议会丢失或重排数据,不能满足 MQTT 协议的传输需要。

1.6 MQTT 协议的工作模型

MQTT 是基于发布 - 订阅模型 (pub/sub) 的消息传递协议,与请求 - 响应模型不同,发布 - 订阅模型主要有三种角色:publisher & subscriber & subscriber

当 client 发布某个主题的消息时,broker 会将该消息分发给任何已订阅该主题的 client。通常来说,client 不会存储消息,一旦消息被发送到这些 client,消息就会从 broker 上删除。另外,保留消息、持久连接和服务质量 QoS 可能会导致消息临时存储在 broker 上。

发布 - 订阅模式使得 消息的发布者和订阅者解耦,主要体现为空间解耦和时间解耦:

图片引用自 https://juejin.cn/post/6976441705067184135 —— cxuan 著


2. MQTT 协议消息格式

2.1 MQTT 协议消息的特点

2.2 MQTT 协议消息基本结构

一个 MQTT 消息由三部分组成:

MQTT 消息结构 描述 长度
固定报头(Fixed header) 存在于所有 MQTT 消息中 2 到 5 字节
可变报头(Variable header) 存在于部分 MQTT 消息中 0 或 N 字节
载荷(Payloads) 存在于部分 MQTT 消息中 0 或 N 字节

1、固定报头: 每一个 MQTT 消息都包含一个固定报头,包含消息类型、标志位和剩余长度三个部分。固定报头长度为 2 ~ 5 字节,具体取决于 “剩余长度” 的大小,格式如下:

消息类型 消息流转方向 描述 需要有效载荷
Reserved 0 禁止 保留 /
CONNECT 1 => 客户端请求连接服务器
CONNACK 2 <= CONNECT 消息确认
PUBLISH 3 <==> 客户端发布消息 可选
PUBACK 4 <==> PUBLISH 消息确认(QoS 1)
PUBREC 5 <==> 发布收到(保证交付第一步)
PUBREL 6 <==> 发布释放(保证交付第二步)
PUBCOMP 7 <==> 发布完成(保证交付第三步)
SUBSCRIBE 8 => 客户端订阅消息
SUBACK 9 <= SUBSCRIBE 消息确认
UNSUBSCRIBE 10 => 客户端取消订阅
UNSUBACK 11 <= UNSUBSCRIBE 消息确认
PINGREQ 12 => 心跳请求
PINGRESP 13 <= PINGREQ 消息确认
DISCONNECT 14 => 客户端断开连接
Reserved 15 禁止 保留 /

提示: 如何判断剩余长度的字节数,采用的是前缀无歧义的表示法。

2、可变报头: 不同消息的可变报头内容不一样,不过其中有一个比较通用的字段:

3、载荷: 某些 MQTT 消息会包含一个有效载荷,对于 PUBLISH 消息来说,有效载荷就是应用消息。


3. MQTT 协议中的消息

3.1 连接消息

MQTT 的连接总是发生在 client 和 broker 之间,两个 client 之间不会互相感知。请求连接时,client 会向 broker 发送 CONNECT 连接消息,broker 接受连接后会响应 CONNACK 连接确认消息。一旦连接建立,连接会一直保持打开状态,直到 client 发送 DISCONNECT 断开连接消息或连接异常中断。

3.1.1 CONNECT 请求连接

CONNECT 是 client 发送给 broker 的首个消息,并且在一次连接中,client 只能发送一次 CONNECT 消息,发送的第二个 CONNECT 消息会被 broker 当作违反协议处理,并断开连接。在 CONNECT 消息中,主要包含以下内容:

3.1.2 CONNACK 连接确认

CONNACK 消息用于确认 CONNECT 消息。CONNECT 是 client 发送给 broker 的首个消息,相应地,broker 发送给 client 的首个消息一定是 CONNACK 消息。在 CONNACK 消息中,主要包含以下内容:

返回码 描述
0 连接已接受
1 连接被拒绝,不可接受的协议版本
2 连接被拒绝,标识符被拒绝
3 连接被拒绝,服务器不可用
4 连接被拒绝,用户名或密码错误
5 连接被拒绝,未授权

3.1.3 DISCONNECT 断开连接

DISCONNECT 消息由 client 发送给 broker,用于断开连接。DISCONNECT 消息没有可变报头和有效载荷,也没有对应的确认应答消息,表示一个干净利索地断开连接操作。断开连接后,client 不能再发送除 CONNECT 消息之外的消息,broker 也需要丢弃和当前会话有环的遗嘱消息。

3.2 订阅消息

MQTT 是基于发布订阅模型的协议,在建立连接后,client 可以向 broker 订阅感兴趣的一个或多个话题。

3.2.1 SUBSCRIBE 订阅

SUBSCRIBE 消息由 client 发送给 broker,用于订阅感兴趣的话题,SUBSCRIBE 消息主要包含以下内容:

3.2.2 SUBACK 订阅确认

SUBACK 消息用于确认 SUBSCRIBE 消息。SUBACK 消息主要包含以下内容:

返回码 描述
0x00 订阅成功,最大 QoS 为 0
0x01 订阅成功,最大 QoS 为 1
0x02 订阅成功,最大 QoS 为 2
0x80 订阅失败

3.2.3 UNSUBSCRIBE 退订

UNSUBSCRIBE 消息由 client 发送给 broker,用于退订不感兴趣的话题,UNSUBSCRIBE 消息主要包含以下内容:

3.2.4 UNSUBACK 退订确认

UNSUBACK 消息用于确认 UNSUBSCRIBE 消息。UNSUBACK 消息非常简单,只有一个包唯一标识(位于可变报头)。

3.3. 发布消息

当 MQTT client 在连接到 broker 之后就可以发送消息了,每条 PUBLISH 消息都包含一个 topic ,broker 会根据 topic 将消息发送给感兴趣的 client。除此之外,每条消息还会包含一个 Payload,Payload 是真正发布的应用消息,载荷的内容和格式由应用层决定,MQTT 协议层不关心。

3.3.1 PUBLISH 发布

PUBLISH 消息可以由 client 发送给 broker,也可以由 broker 发送给 client,用来运送应用层消息。PUBLISH 消息主要包含以下内容:

3.3.2 发布确认

PUBLISH 消息的接收方需要发送确认应答,不同 QoS 等级的 PUBLISH 消息响应的消息不同:

发布服务质量等级 QoS 期望的确认应答
QoS 0 无确认应答
OoS 1 PUBACK 消息
OoS 2 PUBREC 消息
PUBREL 消息
PUBCOMP 消息

3.4 Ping 心跳探测

当 client 和 broker 在一段时间内没有数据交互时,client 会发送 PINGREQ 探测消息,用于判断连接是否正常,来决定是否要关闭该连接,这就是 MQTT 协议的保活机制。

3.4.1 PINGREQ 探测消息

PINGREQ 消息由 client 发送给 broker。

3.4.2 PINGRESP 探测确认

PINGRESP 消息由 broker 发送给 client,代表 client 是存活的。


4. MQTT 协议核心特性

4.1 主题和主题过滤器

MQTT 主题本质上是一种 “寻址形式”,用于将应用层消息分发到期望的客户端。MQTT 主题是一种类似于文件系统的分层结构,使用 “/” 正斜杠 作为分隔符。

4.1.1 主题格式规范

4.1.2 主题通配符

客户端订阅主题时,可以订阅确定的主题(例如 “group/group123”),也可以使用 “通配符” 来同时订阅多个主题。需要注意的是:在发布消息是不允许使用主题通配符,client 每次发布消息只能发布到单个主题。

主题 匹配主题举例
group/+/123 group/vip/123
group/temp/123
主题 匹配主题举例
group/# group
group/123
group/vip/123
group/temp/123

4.1.3 $SYS 主题

$SYS 主题是 broker 上默认创建的只读主题,除此之外,broker 不会默认创建任何主题,所有主题都是由客户端订阅或发布才创建的,都不是永久性的。关于 $SYS 主题的更多介绍在 这里

4.1.4 主题的生存周期

4.2 会话状态

当 client 连接到 broker 时,可以使用持久连接或非持久连接,这是通过 CONNECT 消息中的 CleanSession 标志来决定的(当 CleanSession = 0 时表示持久连接)。对于持久会话,broker 会存储会话状态;而对于非持久会话,broker 不会存储 client 的任何内容。会话状态主要包含以下内容:

4.2.1 客户端存储的会话状态

4.2.2 服务端存储的会话状态

提示: 保留消息不属于会话状态,在会话结束时不会被删除,broker 应该一直存储保留消息知道被 client 删除。

4.3 QoS 发布服务质量等级

QoS 0 等级的 PUBLISH 消息的交付能力完全依赖于底层传输层,QoS 1 和 QoS 2 等级开始在应用层提高 PUBLISH 消息的交付能力。当消息丢失时,发送端会重新发送早前尝试发送过的 PUBLISH 消息(DUP = 1),接收者收到消息也会发送确认响应消息。

4.3.1 QoS 0 · 最多发一次

在 QoS 0 的等级的 PUBLISH 消息中不包含包唯一标识。发送者不考虑消息交付结果,接收者也不发送响应。接收者最多只能收到一次消息,也有可能一次也收不到。

4.3.2 OoS 1 · 最少发一次

在 QoS 1 等级的 PUBLISH 消息中包含包唯一标识,发送方会一直将该消息当作 “未确认” 的消息,直到收到对应的 PUBACK 确认消息。具体消息流如下:

提示: 实际的消息传递是在 client 和 broker 之间进行的,这里描述了发送方和接收方之间的消息传递。

4.3.3 QoS2 · 正好发一次

QoS 2 是最高的服务质量,保证消息不会丢失也不会重复,缺点是会增加开销。在 QoS 2 等级的 PUBLISH 消息中包含包唯一标识,发送者会一直将该消息当作 “未确认” 的消息,知道收到对应的 PUBCOMP 确认消息。

4.4 RETAIN 保留消息

当 client 发布某个主题的消息时,broker 会将该消息分发给任何已订阅该主题的 client,随后这条消息会从 broker 上删除。可以设置 RETAIN 保留标志设置该 PUBLISH 消息为保留消息,broker 会存储该主题的最后一条保留消息,当新的 client 注册订阅时,并且匹配该消息主题时,该保留消息会发送给订阅者。需要注意:broker 只会为每个主题保存最近一条保留消息,新收到的 RETAIN = 1 的消息会覆盖原本那条保留消息;

持久会话 & 服务质量等级 & 保留消息都会影响新订阅者是否接受消息,总结如下表:

4.5 消息重传

标记 DUP = 1 的消息是重复发送的消息,MQTT 消息重传有两种场景:

需要注意:DUP 标志只对 OoS > 0 的消息有效,所有 QoS = 0 的消息 DUP 标志必须设置为 0;

TCP 协议有报文重传机制,为什么 MQTT 协议还有消息重传机制?

TCP 协议的报文重传机制是对所有 TCP 报文有效的重传机制,而 MQTT 协议的消息重传机制只对一小部分消息有效,用于实现更可靠的消息交付保证。虽然 TCP 协议在一般情况下可以保证不丢包,但是这并不是绝对的,依然存在请求超时或者连接中断等情况。而 MQTT 协议的 QoS 1 和 QoS 2 要求更可靠的交付能力,并且需要在客户端重连后也能保证交付。因此,MQTT 协议也定义了一个消息重传机制。


5. 总结

到这里,关于 MQTT 协议的工作原理 & 协议消息格式 & 核心特性等内容就介绍完了。我知道你应该会对 MQTT 协议的实战应用更加感兴趣,下一篇文章里,我将带你实现基于 MQTT 协议的 IM 服务,请关注。


参考资料


创作不易,你的「三连」是丑丑最大的动力,我们下次见!

上一篇 下一篇

猜你喜欢

热点阅读