0%

【计算机网络】mqtt 通信协议入门(一)报文结构

想要深入理解某一种网络协议,那么对其报文结构肯定要了如指掌,因为这是其设计的基础,一切功能都是和报文息息相关的。这篇文章就来剖析一下 mqtt 协议的报文结构,这样在日后开发相关通信库的时候,才能够得心应手。

mqtt 控制报文结构

mqtt 协议通过交换预定义的 mqtt 控制报文来进行通信,该控制报文由三部分组成:

  • 固定报头 :mqtt 所有报文均包含该部分
  • 可变报头 :仍然属于报文控制头部,只是并不是所有报文都需要这部分控制信息
  • 有效载荷 :可以理解为数据部分,有些类型的报文不需要

固定报头

image-20240713175057319

报文类型

如上图所示,固定报头至少占两个字节,最多占五个字节,其中第一个字节高四位用于指定控制报文的类型。mqtt 协议共有 14 种控制报文,所以,固定报头高四位值为 015 的报文为保留报文

名称 方向 描述
Reserved 0 保留
Reserved 15 保留

建立、确认与释放连接

连接,连接确认与释放连接的控制报文类型如下:

名称 方向 描述
CONNECT 1 客户端——>服务端 客户端请求连接服务端
CONNACK 2 服务端——>客户端 连接报文确认
DISCONNECT 14 客户端——>服务端 客户端断开与服务端的连接

数据传输相关

mqtt 协议种使用发布 来描述数据传输的过程,包括 :

  • 客户端主动向服务器端发布一个主题
  • 服务器端向客户端发布其订阅的主题消息

这两种通信过程都是使用 PUBLISH 相关报文来进行消息传递的,基于不同的 QoS ,PUBLISH 包含多种行为方式

名称 方向 描述
PUBLISH 3 两个方向都允许 消息发布
PUBACK 4 两个方向都允许 QoS1 消息发布收到确认
PUBREC 5 两个方向都允许 QoS2 消息发布收到(保证交付第一步)
PUBREL 6 两个方向都允许 QoS2 消息发布释放(保证交付第二步)
PUBCOM 7 两个方向都允许 QoS2 消息发布完成(保证交付第三步)

订阅与取消订阅

客户端可以使用订阅和取消订阅报文向服务器表明自己感兴趣的主题,该报文类型如下:

名称 方向 描述
SUBSCRIBE 8 客户端——>服务端 客户端订阅请求
SUBACK 9 服务端——>客户端 服务器端订阅报文确认
UNSUBSCRIBE 10 客户端——>服务端 客户端取消订阅请求
UNSUBACK 11 服务端——>客户端 服务器端取消订阅报文确认

心跳包

客户端发送 心跳 (Keep Alive)PINGREQ 报文给服务端的。用于:

  • 在没有任何其它控制报文从客户端发给服务的时,告知服务端客户端还活着。
  • 请求服务端发送响应确认服务端还活着。
  • 使用网络以确认网络连接没有断开。

服务端发送 心跳响应 PINGRESP 报文响应客户端的 PINGREQ 报文,表示服务端还活着。

名称 方向 描述
PINGREQ 12 客户端——>服务端 客户端心跳请求
PINGRESP 13 服务端——>客户端 服务器端心跳响应

标志位

第一个字节低四位 [3:0],用来包含每个 MQTT 控制报文类型特定的标志

image-20240713183724359

可以看到,大部分类型的报文都不使用标志位,对于 PUBLISH 报文,这些标志位的作用在下文会详细介绍

剩余长度

剩余长度字段描述了 可变报头+有效载荷 的长度,使用变长编码方案,最大支持四个字节,具体规则如下:

image-20240713185158034

每个字节的低 7 位用于编码数据最高位是标志位,标志位标志着剩余长度字段是否已经结束。举个例子长度为16383 字节的,如下编码:

第一字节:1111 1111 ==> 标志位为 1 ,代表该字段未结束,此字节有效数据 111 1111

第二字节:0111 1111 ==> 标志位为 0 ,代表该字段已结束,此字节有效数据 111 1111

最终有效数据 :111 1111 111 11110x3FFF (16383)

可变报头

报文标识符

某些MQTT控制报文包含一个可变报头部分。它在固定报头和负载之间。可变报头的内容根据报文类型的不同而不同可变报头的报文标识符(数据包标识符)字段存在于在多个类型的报文里。

image-20240713185906710

对于是否使用以及如何使用报文标识符,要遵循以下规则:

  • PUBLISH 发布相关的报文:

    • QoS0 时,PUBLISH 不能使用报文标识符
    • QoS > 0 时,PUBLISH 必须包含一个非零的 16 位报文标识符
    • QoS1 时,PUBACK 报文必须包含与最初发送的 PUBLISH 报文相同的报文标识符
    • QoS2 时,PUBACKPUBRECPUBRELPUBCOMP 报文必须包含与最初发送的 PUBLISH 报文相同的报文标识符
  • SUBACKUNSUBACK 必须包含在对应的 SUBSCRIBEUNSUBSCRIBE 报文中使用的报文标识符

  • 对客户端和服务器端来说(订阅与取消订阅只与客户的相关):

    • 每次发送一个新的这些类型的报文时都必须分配一个当前未使用的报文标识符。

    • 重发报文时,必须使用与上一次相同的标识符。

    • 当处理完这个报文对应的确认(QoS1的 PUBLISH 对应确认的是 PUBACK,Q0S2的 PUBLISH 对应确认的是 PUBCOMP,与 SUBSCRIBEUNSUBSCRIBE 对应确认的分别是 SUBACKUNSUBACK)后,这个报文标识符就释放可重用

image-20240713190450113

其他部分

除了报文标识符,可变报头还包括其他部分,不过剩余部分和各个控制报文息息相关,后面再详细介绍。

有效载荷

某些 mqtt 控制报文会在报文最后部分包含一个有效载荷,对于 PUBLISH 报文,其有效载荷就是应用消息。下面列出了需要有效载荷的控制报文类型。

image-20240713223918296