MQTT协议

一.MQTT简介

MQTT(Message Queuing Telemetry Transport 消息队列遥测传输),是一种轻量级、低带宽消耗、低资源占用的 发布/订阅 (Pub/Sub)模式通信协议。它最初由IBM开发,最初用于石油行业远程设备数据采集, 如今已成为物联网(IoT)、工业互联网(IIoT)、智能家居等场景的核心通信协议。MQTT被广泛用于物联网(IoT:Internet of Things)领域,其中大量的设备需要进行实时通信和数据交换。它采用了 一种发布/订阅(publish/subscribe)模型,其中消息的发送者(发布者)将消息发布到特定的主题(topic),而订阅者可以选择性地订阅感兴趣的主题,以接收相应的消息。

二.MQTT的特点

1.轻量级

MQTT的设计非常轻量,协议头部非常小,传输的数据量很小,适用于带宽有限的网络环境,如低速、高延迟或不稳定的网络

2.异步通信

MQTT使用异步通信模式 ,发布者发送消息后,不需要等待接收者的响应,可以继续执行其他操作。这种异步通信模式适合在资源有限的设备和网络中工作。

3.简单

MQTT的协议规范相对简单,易于实现和部署。它定义了少量的消息类型和协议操作,使得开发人员可以快速上手。

4.可靠性

MQTT支持三种不同的消息传递质量(QoS)级别:QoS 0(至多一次),QoS 1(至少一次)和QoS 2(只有一 次) 。这使得可以根据应用程序的要求选择适当的消息交付保证级别。

5.网络状况适应性

MQTT可以适应不稳定的网络状况,如网络中断、重连等。它具有断开连接后自动重连的机制,可以确保消息的可靠传输。

三.MQTT通信架构的三角色

MQTT的通信架构由发布者(Publisher)、订阅者(Subscriber)、Broker(代理服务器) 三个核心角色组成,
三者协同实现消息流转:

四.MQTT的主要概念

1.主题(Topic):消息的"地址"

Topic是MQTT中消息的分类标识,类似 "文件夹路径",采用斜杠(/)分层Subscriber通过订阅Topic接收特定消息, Publisher通过指定 Topic发送消息。一个主题可以有多个订阅者,代理会将该主题下的消息转发给所有订阅 者;一个主题也可以有多个发布者,代理将按照消息到达的顺序发。
常见Topic格式:智能家居: home/livingroom/light/status (客厅灯状态)、 home/bedroom/temp (卧室温度)
特殊Topic:通配符
订阅时可使用通配符匹配多个Topic,发布消息时不支持通配符 :
+(单层通配符):匹配一层Topic,如订阅home/+/temp ,可接收home/livingroom/temp home/bedroom/temp ,但无法接收 home/bedroom/temp/humidity 。
#(多层通配符):匹配当前及所有子层Topic(必须放在Topic末尾),如订阅home/# ,可接收
home/livingroom/light 、 home/bedroom/temp/humidity 等所有以 home/ 开头的Topic。

2.客户端标识符(Client ID)

每个连接到Broker的设备(Publisher/Subscriber)必须有唯一的Client ID,用于Broker识别设备、维护会话 (如持久会话的消息存储)。若 Client ID重复,Broker 会断开先连接的设备。

五.MQTT QoS

1.QoS介绍:

很多时候,使用MQTT协议的设备都运行在网络受限的环境下,**而只依靠底层的TCP传输协议,并不能完全保证消息的可靠到达。**因此,MQTT提供了QoS(Quality of Service)机制,其核心是设计了多种消息交互机制来提供不同的服务质量,来满足用户在各种场景下对消息可靠性的要求。MQTT(Message Queuing Telemetry Transport)协议支持三种不同的QoS级别,用于控制消息的可靠性和传输保证。

MQTT的三个QoS级别:QoS 0(至多一次),QoS 1(至少一次)和QoS 2(只有一次)。

2.QoS 0(至多一次)

在QoS 0级别下,消息以**"至多一次"传输,没有确认机制。消息被发布后,发布者不会接收到关于消息是否成功传输或交付的确认。MQTT代理会尽最大努力将消息传输给订阅者,但可能会出现消息丢失或重复的情况。此级别适用于对消息传输的可靠性要求不高的场景,如传感器数据的临时更新等。

为什么 QoS 0 消息会丢失?
当我们使用QoS 0传递消息时,消息的可靠性
完全依赖于底层的TCP协议。**而TCP只能保证在连接稳定不关闭的情况下消息的可靠到达,一旦出现连接关闭、重置,仍有可能丢失当前处于网络链路或操作系统底层缓冲区中的消息。这也是QoS 0消息最主要的丢失场景。

3.QoS 1(至少一次)

为了保证消息到达,QoS 1加入了应答与重传机制,**发送方只有在收到接收方的PUBACK报文以后,才能认为消息投递成功,**在此之前,发送方需要存储该PUBLISH报文以便下次重传。
如果发布者没有收到确认消息,它会再次发送相同的消息,直到收到确认为止。MQTT代理会确保消息至少传输一次给订阅者,但可能会出现重复传输的情况。此级别适用于对消息传输的可靠性要求较高的场景,如控制指令的传递。
QoS 1需要在PUBLISH报文中设置Packet ID,而作为响应的PUBACK报文,则会使用与PUBLISH报文相同的Packet ID,以便发送方收到后删除正确的 PUBLISH报文缓存。

4.QoS 2(只有一次)

在QoS 2级别下,消息以"只有一次"传输,确保仅传输一次。发布者发送消息后,会等待MQTT代理发送两个确认消息 (PUBREC和PUBCOMP)来确认消息的接收和完成。MQTT代理会确保消息仅传输一次给订阅者,没有重复传输的情况。
此级别提供了最高的消息传输可靠性,但也伴随着更高的网络开销。此级别适用于对消息传输的可靠性要求非常高的场景,如金融交易或严格的数据同步。
PUBREC -- 发布收到报文 (QoS 2,第一步);
PUBREL -- 发布释放(QoS 2,第二步);
PUBCOMP-- 发布完成(QoS 2,第三步)
oS 2解决了QoS 0、1消息可能丢失或者重复的问题,但相应地,它也带来了最复杂的交互流程和最高的开销。每一次的QoS 2****消息投递,都要求发送方与接收方进行至少两次请求/响应流程。

首先,发送方
存储并发送 QoS 为 2 的PUBLISH报文
以启动一次QoS 2消息的传输,然后等待接收方回复PUBREC报文。这一部分与 QoS 1 基本一致,只是响应报文从PUBACK变成了PUBREC。
发送方收到****PUBREC报文,即可确认对端已经收到了PUBLISH 报文,发送方将不再需要重传这个报文,并且也不能再重传这个报文。所以此时发送方可以删除本地存储的 PUBLISH 报文,然后
发送一个PUBREL报文,通知对端自己准备将本次使用的Packet ID **标记为可用了。**与PUBLISH报文一样,我们需要确保PUBREL报文到达对端,所以也需要一个响应报文,并且这个PUBREL报文需要被存储下来以便后续重传。
当接收方收到PUBREL报文,也可以确认在这一次的传输流程中不会再有重传的PUBLISH报文到达,因此回复PUBCOMP报文表示自己也准备好将当前的Packet ID用于新的消息了。
当发送方收到PUBCOMP报文,这一次的QoS 2消息传输就算正式完成了。在这之后,发送方可以再次使用当前的Packet ID发送新的消息,而接收方再次收到使用这个Packet ID的PUBLISH报文时,也会将它视为一个全新的消息。
选择合适的QoS级别取决于应用程序对消息传输可靠性和网络开销的要求。更高的QoS级别提供了更可靠的传输,但同时也增加了网络开销。因此,需要根据具体场景的需求来选择适当的级别。

六.MQTT协议格式分析

<1>MQTT固定头

固定头 存在于所有 MQTT数据包中,大小为俩个字节,其结构如下:

1.MQTT消息类型/ message type
2 标识位 / DUP

重发标识(Dup Flag)。如果DUP标志被设置为0,表示这是客户端或服务端第一次发送这个PUBLISH报文,如果DUP标志被设置为1,表示这可能是一个早期报文请求的重发。客户端或服务器端请求重发一个PUBLISH报文时,必须将DUP标志设置为1.对于QoS为0的消息,DUP标志必须设置为0

3 QoS发布消息的服务质量

00:最多一次 01:至少一次 10:只有一次 11:预留

4.RETAIN发布保留标识

发布保留标识,表示服务器要保留这次推送的信息,如果有新的订阅者出现,就把这消息推送给它,如果设有那么推送至当前订阅者后释放。

5 剩余长度(Remaining Length)

剩余长度字段使用了一种可变长度编码方式,可以占用1到4个字节。每个字节的最高位(bit 7)表示后续字节是否是剩余长度的一部分。如果最高位为1**,表示后续字节也是剩余长度的一部分;如果最高位为0,则表示这是最后一个字节,不再是剩余长度的一部分。**
如果第一个字节的最高位为0,则说明剩余长度只有一个字节,并且其值就是这个字节的值。
如:0100 0000 那么剩余长度的真实值就是:64。
如果剩余长度超过一个字节,那么就需要将每个字节的最高位去掉,然后组成一个新的数据,计算其值,下面举例说明: 2个字节长度的剩余长度计算。
第一个字节为 1010 0000 第二个字节为 0000 0001
去掉标志位后,第一个字节为 010 0000 第二个字节为 000 0001
合并时,后面的字节在高位,则合并后值为:000 0001 010 0000,则剩余长度的值为十进制的160;

<2>MQTT可变头 / Variable header

MQTT数据包中包含一个可变头,它驻位于固定的头和负载之间。可变头的内容因数据包类型而不同,较常的应用是做为包的ID标识:

很多类型数据包中都包括一个2字节的数据包标识字段,这些类型的包有: PUBLISH (QoS > 0)、PUBACK、PUBREC、PUBREL、PUBCOMP、SUBSCRIBE、SUBACK、UNSUBSCRIBE、UNSUBACK。。

<3>Payload****消息体

Payload消息体是MQTT数据包的第三部分,Payload意思是消息载体的意思。如PUBLISH的Payload就是应用程序发布的消息内容。还有一些消息类型,携带的payload含有特殊含义的数据。如CONNECT、SUBSCRIBE、SUBACK、UNSUBSCRIBE四种类型的消息有消息体:
CONNECT 消息体内容主要是:客户端的ClientID、订阅的Topic、以及用户名和密码;
SUBSCRIBE 消息体内容是一系列的要订阅的主题以及QoS;
SUBACK 消息体内容是服务器对于SUBSCRIBE所申请的主题及QoS进行确认和回复。
UNSUBSCRIBE 消息体内容是要订阅的主题。

相关推荐
RockHopper20253 天前
基于MQTT和Sparkplug B的UNS系统的元数据管理
mqtt·元数据管理·uns 统一命名空间·sparkplug b
2401_841495644 天前
【计算机网络】计算机网络体系结构与参考模型
网络·计算机网络·ip·tcp·osi·分层结构·协议数据单元
安娜的信息安全说5 天前
深入浅出 MQTT:轻量级消息协议在物联网中的应用与实践
开发语言·物联网·mqtt
NiKo_W7 天前
Linux TcpSocket编程
linux·服务器·网络·udp·socket·多线程·tcp
kaka❷❷7 天前
STM32 单片机 ESP8266 联网 和 MQTT协议
stm32·单片机·嵌入式硬件·物联网·mqtt·esp8266
EMQX11 天前
ESP32 + MCP over MQTT:实现智能设备语音交互
人工智能·mqtt·语言模型·智能硬件
普中科技11 天前
【普中Hi3861开发攻略--基于鸿蒙OS】-- 第 29 章 WIFI 实验-TCP 通信
单片机·嵌入式硬件·tcp·liteos·hi3861·普中科技
绿萝瀑布12 天前
FreeRTOS互斥量实战:血氧监测系统设计
freertos·嵌入式软件·互斥量