Files
obsidian_sycn/网络通讯/车联网/通讯协议/MQTT 协议是个啥?这篇文章告诉你! - 程序员cxuan - 博客园.md
T
2026-07-31 15:28:08 +08:00

175 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
doc_type: hypothesis-highlights
url: 'https://www.cnblogs.com/cxuanBlog/p/14917187.html'
---
## Metadata
- Author: [cnblogs.com]()
- Title: MQTT 协议是个啥?这篇文章告诉你! - 程序员cxuan - 博客园
- Reference: https://www.cnblogs.com/cxuanBlog/p/14917187.html
- Category: #article
## Page Notes
## Highlights
![image](https://myonemanager.lzybetter.repl.co/picbed_big/picbed/abd5baa3d078f37535e2d82720b201b6.png)
- 还有一个优势就是 MQTT 在客户端容易实现,而且具有易用性,非常适合当今资源有限的设备。
- MQTT 协议与 HTTP 相比具有一个明显的优势:数据包开销较小
- pub/sub 最重要的方面是 publisher 与 subscriber 的解藕
- 空间解耦
- 时间解藕
- 同步 Synchronization 解藕
- 发布/订阅模式消除了传统客户-服务器之间的直接通信,把通信这个操作交给了 broker 进行代理,并在空间、时间、同步三个维度上进行了解藕。
- pub/sub 比传统的客户端-服务器模式有了更好的拓展,这是由于 broker 的高度并行化,并且是基于事件驱动的模式。事件驱动中的程序流程会由诸如用户操作(点击鼠标、键盘)、传感器输出或者从其他程序或传递的消息事件决定。- 事件驱动编程是图形用户界面和其他应用程序比如 Web 中使用的主要范式,这些应用程序能够响应用户输入执行某些操作为中心,这同时也适用于驱动程序的编程 。
- broker 能够对消息进行过滤,使每个订阅者只接收自己感兴趣的消息:
- 基于主题的过滤:每条消息都会有一个 topic ,接收客户端会向 borker 订阅感兴趣的 topic,订阅后,broker 就会确保客户端收到发布到 topic 中的消息
- 基于内容的过滤 :broker 会根据特定的内容过滤消息,接受客户端会经过过滤他们感兴趣的内容。这种方法的一个显著的缺点就是必须事先知道消息的内容,不能加密或者轻易修改
- 基于类型的过滤
- 为了发布/订阅系统的挑战,MQTT 具有三个服务质量级别,你可以指定消息从客户端传到 broker 或者从 broker 传到客户端,在 topic 的订阅中,会存在 topic 没有 subscriber 订阅的情况,作为 broker 必须知道如何处理这种情况。
- 订阅发布模式与消息队列模式区别
- 在传统的消息队列模式中,一条消息会存储在消息队列中等待被消费,每个传入的消息都存储在消息队列中,直到它被客户端(通常称之为消费者)所接收,如果没有客户端消费消息的话,这条消息就会存在消息队列中等待被消费。但是在消息队列中,不会存在消息没有客户端消费的情况,但是在 MQTT 中,确存在 topic 无 subscriber 订阅的情况。
- 在传统的消息队列模式中,一条消息只能被一个客户端所消费,负载会分布在队列的每个消费者之间;而在 MQTT 中,每个订阅者都会受到消息,每个订阅者有相同的负载。
- 在传统的消息队列模式中,必须使用单独的命令来显式创建队列,只有队列创建后,才可以生产或者消费消息;而在 MQTT 中,topic 比较灵活,可以即时创建。
- MQTT基本概念
- MQTT Client
- publisher 和 subscriber 都属于 MQTT Client。
- 发布和订阅的功能也可以由同一个 MQTT Client 实现。
- MQTT 客户端是指运行 MQTT 库并通过网络连接到 MQTT broker 的任何设备,这些设备可以从微控制器到成熟的服务器.
- MQTT Broker
- broker 负责接收所有消息,过滤消息,确定是哪个 client 订阅了每条消息,并将消息发送给对应的 client,broker 还负责保存会话数据,这些数据包括订阅的和错过的消息。broker 还负责客户端的身份验证和授权。
- MQTT 是基于 TCP/IP 协议基础之上的,所以 MQTT 的 client 和 broker 都需要 TCP/IP 协议的支持。
- MQTT链接
- MQTT 的连接总是在 client 和 broker 之间进行,client 和 client 之间并不会相互连接。如果要发起连接的话,那么 client 就会向 broker 发起 CONNECT 消息,代理会使用 CONNACK 消息和状态码进行响应
- 一旦 client 和 broker 的连接建立后,broker 就会使客户端的连接一直处于打开状态,直到 client 发出断开命令或者连接中断。
- 消息
- MQTT 的消息报文主要分为 CONNECT 和 CONNACK 消息。
- CONNECT
- 为了初始化连接,需要 client 向 broker 发送 CONNECT 消息
- 一个 MQTT 客户端发送一条 CONNECT 连接,这条 CONNECT 连接可能会包含下面这些信息
![image](https://myonemanager.lzybetter.repl.co/picbed_big/picbed/a705b334a0d4cb20f22070038ec1cc98.png)
- ClientId:显而易见,这个就是每个客户端的 ID 标识,也就是连接到 MQTT broker 的每个 client。
- 这个 ID 应该是每个 client 和 broker 唯一的,如果你不需要 broker 持有状态的话,你可以发送一个空的 ClientId,空的 ClientId 会没有任何状态。在这种情况下,ClientSession 需要设置为 true,否则将会拒绝连接。
- CleanSessionCleanSession 会话标志会告诉 broker client 是否需要建立持久会话。在持久会话 CleanSession = false)中,broker 存储 client 的所有订阅以及服务质量(Qos) 是 1 或 2 订阅的 client 的所有丢失的消息。如果会话不是持久的(CleanSession = true),那么 broker 则不会为 client 存储任何内容并且会清除先前持久会话中的所有信息。
- Username/Password MQTT 会发送 username 和 password 进行 client 认证和授权
- LastWillxxx LastWillxxx 表示的是遗愿,client 在连接 broker 的时候将会设立一个遗愿,这个遗愿会保存在 broker 中,当 client 因为非正常原因断开与 broker 的连接时,broker 会将遗愿发送给订阅了这个 topic(订阅遗愿的 topic)的 client。
- keepAlivekeepAlive 是 client 在连接建立时与 broker 通信的时间间隔,通常以秒为单位。这个时间指的是 client 与 broker 在不发送消息下所能承受的最大时长。
- CONNACK
- 当 broker 收到 CONNECT 消息时,它有义务回复 CONNACK 消息进行响应
- CONNACK 消息包括两部分内容
![](https://myonemanager.lzybetter.repl.co/picbed_big/picbed/43255ffc270491b4b99a411422899b01.png)
- SessionPresent:会话当前标识,这个标志会告诉 client 当前 broker 是否有一个持久性会话与 client 进行交互。 SessionPresent 标志和 CleanSession 标志有关,当 client 在 CleanSession 设置为 true 的情况下连接时,SessionPresent 始终为 false,因为没有持久性会话可以使用。如果 CleanSession 设置为 false,则有两种可能性,如果 ClientId 的会话信息可用,并且 broker 已经存储了会话信息,那么 SessionPresent 为 true,否则如果没有 ClientId 的任何会话信息,那么 SessionPresent 为 false。
- ReturnCodeCONNACK 消息中的第二个标志是连接确认标志。这个标志包含一个返回码,告诉客户端连接尝试是否成功。连接确认标志有下面这些选项。
- 消息类型
- 发布
- MQTT 使用的是基于 topic 主题的过滤。每条消息都应该包含一个 topic ,broker 可以使用 topic 将消息发送给感兴趣的 client。除此之外,每条消息还会包含一个负载(Payload),Payload 中包含要以字节形式发送的数据。
- MQTT 是数据无关性的,也就是说数据是由发布者 - publisher 决定要发送的是 XML 、JSON 还是二进制数据、文本数据
- MQTT 中的 PUBLISH 消息结构如下
![](https://myonemanager.lzybetter.repl.co/picbed_big/picbed/c0633b77a9c1cfb864bf472795e73131.png)
- Packet Identifier:这个 PacketId 标识在 client 和 broker 之间唯一的消息标识。packetId 仅与大于零的 Qos 级别相关
- TopicName:主题名称是一个简单的字符串,/ 代表着分层结构
- Qos:这个数字表示的是服务质量水平,服务质量水平有三个等级:0、1 和 2,服务级别决定了消息到达 client 或者 broker 的保证类型,来决定消息是否丢失
- RetainFlag:这个标志表示 broker 将最近收到的一条 RETAIN 标志位为true的消息保存在服务器端(内存或者文件)。MQTT 服务器只会为每一个 Topic 保存最近收到的一条 RETAIN 标志位为true的消息
- Payload:这个是每条消息的实际内容
- Dupflag:这个标志表示该消息是重复的并且由于预期的 client 或者 broker 没有确认所以重新发送了一次。
- 当 client 向 broker 发送消息时,broker 会读取消息,根据 Qos 的级别进行消息确认,然后处理消息。处理消息其实就是确定哪些 subscriber 订阅了 topic 并将消息发送给他们。
- 发布消息的 client 不会知道是否有人对发布的消息感兴趣,同时也不知道多少 client 从 broker 收到了消息。
- 订阅
- client 会向 broker 发送 SUBSCRIBE 消息来接收有关感兴趣的 topic,这个SUBSCRIBE 消息非常简单,它包含了一个唯一的数据包标识和一个订阅列表
![](https://myonemanager.lzybetter.repl.co/picbed_big/picbed/400a2de3b1cca165e543c3de7214eab6.png)
- Packet Identifier:这个 PacketId 和上面的 PacketId 一样,都表示消息的唯一标识符。
- ListOfSubscriptionsSUBSCRIBE 消息可以包含一个 client 的多个订阅,每个订阅都会由一个 topic 和一个 Qos 构成。订阅消息中的 topic 可以包含通配符。
- 确认消息
- client 在向 broker 发送 SUBSCRIBE 消息后,为了确认每个订阅,broker 会向 client 发送 SUBACK 确认消息。这个 SUBACK 包含原始 SUBSCRIBE 消息的 packetId 和返回码列表。
![](https://myonemanager.lzybetter.repl.co/picbed_big/picbed/2a0be7b3a5825b41d6282c893853f137.png)
- 发布 - 订阅 - 确认消息,这三种消息的示意图如下。
![](https://myonemanager.lzybetter.repl.co/picbed_big/picbed/1617d6fdc0aba70e124f06bded808008.png)
- 退订
- SUBSCRIBE 消息对应的是 UNSUBSCRIBE 消息,这条消息发送后,broker 会删除关于 client 的订阅。
![](https://myonemanager.lzybetter.repl.co/picbed_big/picbed/e8ce80a3cb32f0f98372e2ade155df75.png)
- 确认退订
- 取消订阅也需要 broker 的确认,此时 broker 会向 client 发送一个 UNSUBACK 消息。
![](https://myonemanager.lzybetter.repl.co/picbed_big/picbed/0b069167a84eaf73290022c071ef8456.png)
- 退订和确认退订的流程如下
![](https://myonemanager.lzybetter.repl.co/picbed_big/picbed/e3d655c72474894f37c5e02cb2719edf.png)
- Topic
- MQTT Topic 非常轻量级,client 在发布或订阅之前不需要先创建所需要的 Topic,broker 在接收每个 Topic 前不用进行初始化操作。
- 当客户端订阅 Topic 时,它可以订阅已发布消息的确切 Topic,也可以使用通配符来同时订阅多个 Topic
- 单级通配符可以替换 Topic 的一个级别,+ 号代表 Topic 中的单级通配符
- 多级通配符涵盖多个 Topic,# 代表 Topic 中的多级通配符。为了让 broker 能够确定和哪些 Topic 匹配,多级通配符必须作为 Topic 中的最后一个字符放置,并以 / 开头
- 当 client 订阅带有多级通配符的 Topic 时,不论 Topic 有多长多深,它都会收到通配符之前 Topic 的所有消息。如果你只将 Topic 定义为 # 的话,那么你将会收到所有的消息。