MQTT简介
MQTT,作为一种专为物联网(IoT)设备间通信而精心设计的发布/订阅协议,它摒弃了HTTP传统的请求/响应模式,转而采用了一种更为灵活的事件驱动机制。这种机制允许MQTT以推送的方式将消息直接传递给客户端,从而实现了实时性和效率的优化。 该架构的核心优势在于其解耦设计,它有效地将数据的生产者和消费者分离,消除了两者之间的直接依赖关系。这种解耦不仅增强了系统的灵活性和可维护性,还为实现高度可扩展的解决方案提供了可能。 在MQTT生态系统中,两个关键组件负责建立连接、发布和订阅消息:MQTT客户端和MQTT代理(Broker)。客户端是连接物联网设备的接口,负责发送和接收消息;而代理则作为中央枢纽,负责消息的路由和分发,确保信息能够准确、及时地传递给目标客户端。
MQTT核心概念
发布订阅
MQTT基于发布订阅模式,其中发布者发布消息到特定的主题,而订阅者订阅这些主题以接收消息。发布者和订阅者之间不需要直接连接,所有的消息都是通过MQTT代理(Broker)进行路由和转发的。
服务端(Broker)
MQTT服务端(Broker)是MQTT协议中的核心组件,它负责接收客户端的连接、接收发布者发布的消息、根据订阅关系将消息分发给相应的订阅者,并维护客户端的会话信息。Broker是发布者和订阅者之间的桥梁。
客户端
MQTT客户端是使用MQTT协议连接到MQTT服务端的设备或应用程序。客户端可以是发布者,也可以是订阅者,或者同时是两者。客户端通过与服务端建立连接,发送和接收MQTT消息。
主题(Topic)
主题是MQTT消息的一个标识符,用于标识和区分不同的消息。发布者发布消息到特定的主题,而订阅者订阅自己感兴趣的主题来接收相关的消息。主题可以是多层次的,使用斜杠(/)分隔。
通配符
MQTT支持使用通配符来订阅多个主题。单层通配符(+)用于匹配主题中的任意一级,而多层通配符(#)用于匹配主题中的任意多级。通配符使得订阅者可以更加灵活地订阅多个相关的主题。
QoS(消息服务质量)
MQTT定义了三种QoS等级,以确保消息的可靠传输。QoS 0表示最多一次,QoS 1表示至少一次,QoS 2表示只有一次。QoS越大,消息的传输复杂程度也越高,但可靠性也越高。
会话(Session)
MQTT会话是客户端与服务端之间的一种持久连接,用于维护客户端的订阅、QoS等信息。当客户端重新连接时,可以选择从已存在的会话中恢复,以保持之前的订阅和QoS设置。
保留消息(Retained Message)
保留消息是一种特殊的MQTT消息,它会被Broker保留并持久化。当新的订阅者订阅该主题时,会立即收到该主题的最新保留消息。这使得订阅者能够立即获取到最新的数据,而不需要等待新的消息发布。
遗嘱消息(Last Will and Testament, LWT)
遗嘱消息是客户端在连接时设置的一种特殊消息。当客户端异常断开连接时,Broker会发布该遗嘱消息到指定的主题,以通知其他客户端该客户端已经离线。这有助于其他客户端感知到某些客户端的状态变化。
共享订阅(Shared Subscriptions)
共享订阅是MQTT 5.0中引入的一个新特性,它允许多个订阅者共享来自单个发布者的消息。在共享订阅中,消息只会被转发给每个订阅组中的一个客户端,从而实现了消息的负载均衡和高可用性。
MQTT的主要优势
轻量级和高效
MQTT 消息格式非常简洁,减少了网络传输的数据量。 协议设计使得它能够在网络带宽有限的情况下工作得很好。
双向通信
MQTT 支持发布/订阅模式,允许设备(发布者)发布消息到特定的主题(topic),同时允许其他设备或服务器(订阅者)订阅这些主题来接收消息。 消息可以广播给多个订阅者,实现了高效的“一对多”通信。
可扩展性
MQTT 的设计允许它在各种规模的物联网生态系统中使用,从几个设备到数百万个设备。 通过使用层次化的主题结构,MQTT 可以有效地管理大量的设备和数据流。
服务质量(QoS)级别
MQTT 提供了三个不同的 QoS 级别,以确保消息的可靠传递。 QoS 0:最多一次(at most once),消息可能会丢失。 QoS 1:至少一次(at least once),消息可能会重复。 QoS 2:恰好一次(exactly once),确保消息只传递一次。
持久会话
MQTT 支持持久会话(Clean Session 标志设置为 false),使得客户端在断开连接后可以重新连接并继续之前的会话,而无需重新订阅所有主题。 这在不稳定或间歇性连接的网络环境中特别有用。
安全特性
MQTT 支持 TLS(Transport Layer Security)加密,以提供传输过程中的数据保密性。 它还支持各种认证机制(如用户名/密码、客户端证书等)来验证客户端的身份。 MQTT 5 版本还引入了更多的安全特性,如消息级别的加密和授权。
跨平台和互操作性
MQTT 是一个开放的标准,由 OASIS MQTT 技术委员会维护。 它有广泛的客户端库和代理软件支持,使得在各种平台和设备上实现 MQTT 通信变得容易。
低延迟
MQTT 协议设计简洁,消息传输速度快,适用于需要快速响应的物联网应用。
易于集成
MQTT 消息可以很容易地与其他系统(如数据库、云服务、大数据分析平台等)集成,以实现数据的收集、存储和分析。
容错性
MQTT 协议具有容错性,可以处理网络中断和设备故障等异常情况,确保系统的稳定性和可靠性。
MQTT协议数据包
MQTT协议的数据包结构简洁而高效,主要由三部分组成,分别是固定头(Fixed header)、可变头(Variable header)和消息体(Payload)。
- 固定头(Fixed header):存在于所有的MQTT数据包中,用于表示数据包类型及对应标志、数据包大小等;
- 可变头(Variable header):存在于部分类型的MQTT数据包中,具体内容是由相应类型的数据包决定的;
- 消息体(Payload):存在于部分的MQTT数据包中,存储消息的具体数据。
固定头(Fixed header)
- 存在范围:出现在所有MQTT数据包中。
- 功能:它包含了一些基础控制信息,比如数据包类型(CONNECT, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, PINGREQ, PINGRESP, DISCONNECT)和数据包的头部标志位,这些标志位用于指示如QoS等级、重传标志、保留消息标志等特性。此外,还包括一个用于表示剩余数据包长度的字段,使得接收方能够事先知道需要读取多少字节来完整解析该数据包。
固定头格式:
| bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| byte 1 | Message Type(消息类型) | DUP flag | QoS level | RETAIN | ||||
| byte 2 | Remaining Length(剩余消息长度) |
消息类型:
Position: byte 1, bits 7-4.(固定头的高四位Bit表示消息类型)
| Mnemonic | Enumeration | Description |
|---|---|---|
| Reserved | 0 | 保留位 |
| CONNECT | 1 | Client 请求连接到 Broker |
| CONNACK | 2 | 链接确认 |
| PUBLISH | 3 | 发布消息 |
| PUBACK | 4 | 发布确认 |
| PUBREC | 5 | 发布收到 |
| PUBREL | 6 | 发布释放 |
| PUBCOMP | 7 | 发布完成 |
| SUBSCRIBE | 8 | Client请求订阅 |
| SUBACK | 9 | 订阅确认 |
| UNSUBSCRIBE | 10 | Client取消订阅 |
| UNSUBACK | 11 | 取消订阅确认 |
| PINGREQ | 12 | Ping 请求 |
| PINGRESP | 13 | Ping 响应 |
| DISCONNECT | 14 | Client 主动断开连接 |
| Reserved | 15 | 保留 |
标志位:
第1个字节的剩余位(低四位bits 3-0)包含了DUP、QoS和RETAIN这三个字段。这些位的位置经过编码,用来表示如下表格所示的标志位。
| 消息类型 | 用途 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|
| PUBLISH | MQTT 3.1.1 使用 | DUP | QoS | QoS | RETAIN |
DUP:当客户端或服务器尝试重新发送PUBLISH、PUBREL、SUBSCRIBE或UNSUBSCRIBE消息时,此标志位将被设置(0:新消息,1:重复消息)。这适用于QoS值大于零(0)且需要确认的消息。当DUP位被设置时,可变头中会包含一个消息ID。 QoS:
| QoS level | bit 2 | bit 1 | Description | ||
|---|---|---|---|---|---|
| 0 | 0 | 0 | 最多一次 | Fire and Forget | <=1 |
| 1 | 0 | 1 | 至少一次 | Acknowledged delivery | >=1 |
| 2 | 1 | 0 | 恰好一次 | Assured delivery | =1 |
| 3 | 1 | 1 | 保留 |
可变头(Variable header)
- 存在范围:并非所有数据包类型都有可变头,其存在与否及具体内容取决于数据包类型。
- 内容:这部分包含一些与数据包类型相关的额外信息。例如,在PUBLISH数据包中,可变头会包含主题名(Topic Name);在CONNECT数据包中,它可能包含协议名称、版本、客户端标识符、清洁会话标志、遗嘱主题、遗嘱消息等;在SUBSCRIBE数据包中,则包含订阅的请求标识符和一个或多个主题过滤器及对应的QoS等级。
消息体(Payload)
- 存在范围:并非所有数据包都包含消息体,是否包含以及其内容同样取决于数据包类型。
- 内容:消息体是数据包的核心内容,存放具体的有效载荷数据。例如,在PUBLISH数据包中,消息体就是实际要发送的数据;在SUBACK数据包中,则是返回给客户端的订阅确认码列表。
其它
关注公众号【 java程序猿技术】获取EMQX实践系列文章
本文使用 markdown.com.cn 排版