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

如题所述

第1个回答  2022-07-06

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

PINGREQ 消息由 client 发送给 broker。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

相似回答