接前一篇文章:ESP32-C3模组上跑通MQTT(2)
本文内容参考:
《ESP32-C3 物联网工程开发实战》
MQTT协议及使用_mqtt endpoint-CSDN博客
你不得不看的图文并茂的MQTT协议通信过程!!!_mqtt流程图-CSDN博客
车联网平台消息传输质量保障|车联网平台搭建从入门到精通 04|qos|通信|可靠性_网易订阅
特此致谢!
上一回对于MQTT协议及其原理作了介绍和讲解,本回继续对于MQTT进行深入讲解。
四、MQTT消息格式
在MQTT协议中,MQTT控制报文由固定头(Fixed Header)、可变头(Variable Header)和消息体(Payload)三部分组成。
1. 固定头
固定头存在于所有MQTT控制报文中。MQTT控制报文固定头说明见下表:
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
第1个字节 | 控制报文的类型 | 用于指定控制报文的标志位 | ||||||
第2个字节 | 剩余长度 |
(1)控制报文的类型
MQTT控制报文的类型占4 bits,一共有14种类型,如下表所示:
名字 | 值 | 报文流动方向 | 描述 |
---|---|---|---|
Reserved | 0 | 禁止 | 保留 |
CONNECT | 1 | 客户端到服务器端 | 客户端请求连接服务器端 |
CONNACK | 2 | 服务器端到客户端 | 连接报文确认 |
PUBLISH | 3 | 两个方向都允许 | 发布消息 |
PUBACK | 4 | 两个方向都允许 | QoS 1消息发布收到确认 |
PUBREC | 5 | 两个方向都允许 | 发布收到(保证交付第一步) |
PUBREL | 6 | 两个方向都允许 | 发布释放(保证交付第二步) |
PUBCOMP | 7 | 两个方向都允许 | QoS 2消息发布完成(保证交互第三步) |
SUBSCRIBE | 8 | 客户端到服务器端 | 客户端订阅请求 |
SUBACK | 9 | 服务器到客户端 | 订阅请求报文确认 |
UNSUBSCRIBE | 10 | 客户端到服务器端 | 客户端取消订阅请求 |
UNSUBACK | 11 | 服务器端到客户端 | 取消订阅报文确认 |
PINGREQ | 12 | 客户端到服务器端 | 心跳请求 |
PINGRESP | 13 | 服务器端到客户端 | 心跳响应 |
DISCONNET | 14 | 客户端到服务器端 | 客户端断开连接 |
(2)消息质量等级
MQTT消息质量有三个等级,即QoS 0、QoS 1和QoS 2。
1)QoS 0
最多分发一次。消息的传输完全依赖底层的TCP/IP网络,MQTT协议里没有定义应答和重试,消息要么只会到达服务器端一次,要么根本没有到达。
如果当时客户端不可用,则会丢失该消息。Sender(可能是Publisher或者Broker)发送一条消息之后,就不再关心它有没有发送到对方,也不设置任何重发机制。
MQTT QoS 0的流程如下图所示:
2)QoS 1
至少分发一次。服务器的消息接收由PUBACK消息进行确认,如果通信链路或发送设备异常、或者在指定时间内没有收到确认消息,则发送端会重发这条报文,并且在MQTT控制报文固定头中设置重发标志位(DUP)。
发布者在每次发送新的应用消息都必须分配一个未使用的报文标识符,在发布消息的同时将消息存储起来,等待服务器的应答,直到从接收者那收到对应的PUBACK报文。发送的PUBLISH报文必须包含报文标识符且QoS等于1,DUP等于0。一旦发布者收到来自服务器的PUBACK报文后,这个报文标识符就可以重复使用。
接收者响应的PUBACK报文必须包含一个报文标识符,这个标识符来自接收到的PUBLISH报文。在发送了PUBACK报文之后,接收者必须将任何包含相同报文标识符的入站PUBLISH报文当作一个新的消息,并忽略它的DUP标志的值。
MQTT QoS 1的流程如下图所示:
3)QoS 2
只分发一次。这是最高级别的服务质量等级,消息丢失和重复都是不可接受的,使用此服务质量等级会有额外的开销。
QoS 2的消息可变报头中有报文标识符。
QoS 2的PUBLISH报文的接收者使用一个两步确认过程来确认收到。
发送者必须给要发送的新应用消息分配一个未使用的报文标识符。发送的PUBLISH报文必须包含报文标识符且报文的QoS等于2,DUP等于0。
在消息发出去后,需要将这个消息存储起来,而且必须将这个PUBLISH报文看作是未确认的,直到从接收者那收到对应的PUBREC报文。
当发布者收到的PUBREC报文后必须发送一个PUBREL报文。PUBREL报文必须包含与原始PUBLISH报文相同的报文标识符。而且发布者还必须必须将这个PUBREL报文看作是未确认的,直到从接收者那收到对应的PUBCOMP报文。一旦发送了对应的PUBREL报文就不能重发这个PUBLISH报文。
MQTT QoS 2的流程如下图所示:
QoS 2对应的分发消息也是比较复杂的,一般有两种处理方案,每一种方案都要确保消息有且只有处理一次。
- 方案1
接收者(此处指服务器)响应的PUBREC报文必须包含报文标识符,这个标识符来自接收到的PUBLISH报文。
发送PUBREC报文后,在收到对应的PUBREL报文之前,接收者可以将消息分发给订阅者,但是必须要存储报文标识符;接收者也可以丢弃存储的报文标识符,而不必再分发应用消息给订阅者。
- 方案2
当然,接收者(此处指服务器)在这种情况下,也可以存储消息,直到收到PUBREL报文才将消息分发到订阅者。
而当它收到PUBREL报文后,它必须发送PUBCOMP报文响应发布者,该报文必须包含与PUBREL报文相同的标识符。
如果此前没有分发应用消息给订阅者,那么此时需要分发应用消息给订阅者,然后丢弃消息。
在接收者发送PUBCOMP报文之后,接收者必须将包含相同报文标识符的任何后续PUBLISH报文当作一个新的发布。
(3)标志位
MQTT控制报文固定头的bit0~bit3为标志位,依照控制报文类型有不同的含义。事实上,除了PUBLISH类型,其它控制报文类型的标志位均为系统保留。在不使用标志位的消息类型中,标志位被作为保留位。如果收到无效的标志,接收端就必须关闭网络连接。
PUBLISH报文头Byte 1中bit0~bit3组成如下:
1)DUP(bit3)
重发标志位。如果DUP标志位被设置为0,则表示这是客户端或服务器端第一次请求发送PUBLISH报文;如果DUP标志被设置为1,则表示这可能是一个早前报文请求的重发。对于QoS 0的消息,DUP标志位必须设置为0。
2)QoS(bit2~bit1)
发布消息的服务质量等级,保证消息传输的次数。QoS值与bit2~bit1的关系如下表所示:
QoS值 | bit2 | bit1 | 描述 |
---|---|---|---|
0 | 0 | 0 | 最多分发一次 |
1 | 0 | 1 | 至少分发一次 |
2 | 1 | 0 | 只分发一次 |
— | 1 | 1 | 保留 |
3)RETAIN(bit0)
保留标志位。如果客户端发给服务器端的PUBLISH报文的保留(RETAIN)标志位被设置为1,则服务器端必须存储这个报文和它的服务质量等级(QoS),以便它可以被分发给未来与主题名匹配的订阅者。在建立一个新的订阅时,对于每个匹配的主题名,如果存在最近保留的消息,则该消息必须被发送给这个订阅者。
RETAIN标志位通常用于遗嘱消息,例如在设备异常离线后,代理服务器会将遗嘱消息告知给智能手机,智能手机就会显示设备离线的状态。
MQTT消息格式的更多内容请看下回。