前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MQTT 5.0 报文解析 01:CONNECT 与 CONNACK

MQTT 5.0 报文解析 01:CONNECT 与 CONNACK

原创
作者头像
EMQ映云科技
发布2024-04-08 11:34:25
1540
发布2024-04-08 11:34:25

在 MQTT 5.0 报文介绍中,我们介绍了 MQTT 报文由固定报头、可变报头和有效载荷三个部分组成,以及可变字节整数、属性这类 MQTT 报文中的通用概念。现在,我们将按照实际的用途来进一步介绍各个类型的报文的组成。首先,我们将专注于用于建立 MQTT 连接的报文。

如果我们想要使用 MQTT 进行通信,第一步必然是建立一个 MQTT 连接,而建立 MQTT 连接需要用到两个控制报文,它们分别是 CONNECT 报文与 CONNACK 报文。CONNECT 报文是客户端与服务端建立网络连接后,向服务端发送的第一个控制报文,用来发起连接请求。服务端将返回 CONNACK 报文告知客户端连接结果。

报文示例

我们使用 MQTTX CLI 向公共 MQTT 服务器发起一个连接,在这个连接中,我们将协议版本设置 MQTT 5.0,Clean Start 设置为 1,Session Expiry Interval 设置为 300 秒,Keep Alive 设置为 60,用户名和密码分别设置为 admin 和 public,对应的 MQTTX CLI 命令为:

代码语言:javascript
复制
mqttx conn --hostname broker.emqx.io --mqtt-version 5 \  --session-expiry-interval 300 --keepalive 60 --username admin --password public

以下是使用 Wireshark 工具抓取到的 MQTTX CLI 发出的 CONNECT 报文,Linux 环境可以先使用 tcpdump 命令抓取报文,然后再导入至 Wireshark 查看:

代码语言:javascript
复制
10 2f 00 04 4d 51 54 54 05 c2 00 3c 05 11 00 00 01 2c 00 0e 6d 71 74 74 78 5f 30 63 36 36 38 64 30 64 00 05 61 64 6d 69 6e 00 06 70 75 62 6c 69 63

但这是一串不易理解的十六进制字节,除非它们被转换成以下格式:

同样我们也抓取到了公共 MQTT 服务器返回的 CONNACK 报文:

代码语言:javascript
复制
20 13 00 00 10 27 00 10 00 00 25 01 2a 01 29 01 22 ff ff 28 01

在解析这串报文数据之后我们可以看到,CONNACK 报文的 Reason Code 为 0,表示连接成功,后面的多个属性则给出了服务器支持的功能列表,比如支持的最大报文长度,是否支持保留消息等等:

当然,Wireshark 其实也已经为我们列出了报文中各个字段的值,通过下文对 CONNECT 和 CONNACK 报文结构的介绍,再结合 Wireshark 的抓包结果按图索骥,你将很快掌握这两个报文:

CONNECT 报文结构

固定报头

CONNECT 报文的固定报头中,位于首字节高 4 位的报文类型字段的值必须为 1(0b0001),首字节中低 4 位则固定全为 0。

所以,CONNECT 报文的第一个字节的值必然为 0x10,我们可以以此来判断某个报文是否为 CONNECT 报文。

可变报头

CONNECT 报文的可变报头按顺序包含以下字段:

  • Protocol Name:这是一个 UTF-8 编码的字符串,用来表示协议名称。在 MQTT 中,UTF-8 编码的字符串的前两个字节统一用于指示后面实际的字符数据的长度。MQTT 3.1.1 和 MQTT 5.0 中协议名称固定为 MQTT,所以对应的以十六进制字节表示的完整内容就是 00 04 4d 51 54 54,其中 4d 51 54 54 就是 MQTT 这个字符串对应的 ASCII 值。最早的 MQTT 3.1 中的协议名称是 MQIsdp,所以它对应的是 00 06 4d 51 49 73 64 70
  • Protocol Version:这是一个单个字节长度的无符号整数,用来表示协议版本。目前只有三个可取值,3 表示 MQTT 3.1,4 表示 MQTT 3.1.1,5 表示 MQTT 5.0。
  • Connect Flags:连接标识,它只有一个字节,但包含了多个用于控制连接行为或指示有效载荷中某些字段是否存在的参数。
  • User Name Flag:用于指示有效载荷是否包含用户名字段。
  • Password Flag:用于指示有效载荷是否包含密码字段。
  • Will Retain:用于指示遗嘱消息是否为保留消息。
  • Will QoS:用于指示遗嘱消息的 QoS。
  • Will Flag:用于指示有效载荷是否包含了遗嘱消息的相关字段。
  • Clean Start:用于指示当前连接是一个新的会话还是一个已存在会话的延续,这决定了服务端将直接新建会话还是尝试复用已存在的会话。
  • Reserved:这是一个保留位,它的值必须为 0。
  • Keep Alive:这是一个双字节长度的无符号整数,用来表示客户端发送两个相邻的控制报文的最大时间间隔。
  • Properties:下表列出了 CONNECT 报文的所有可用属性。

Identifier

Property Name

Type

0x11

Session Expiry Interval

四字节整数

0x21

Receive Maximum

双字节整数

0x27

Maximum Packet Size

四字节整数

0x22

Topic Alias Maximum

双字节整数

0x19

Request Response Information

单字节

0x17

Request Problem Information

单字节

0x26

User Property

UTF-8 字符串对

0x15

Authentication Method

UTF-8 编码的字符串

0x16

Authentication Data

二进制数据

有效载荷

CONNECT 报文有效载荷中的字段,除了 Client ID 以外,其他字段都是可选的,它们是否存在取决于可变报头的 Connect Flags 中对应标志位的值。但如果这些存在,就必须按照 Client ID、Will Properties、Will Topic、Will Payload、User Name、Password 的顺序出现。

CONNACK 报文结构

固定报文

固定报头中首字节的高 4 位值为 2(0b0010),表示这是一个 CONNACK 报文。

可变报头

CONNACK 报文的可变报头按顺序包含以下字段:

  • Connect Acknowledge Flags:连接确认标志。
    • Reserved (Bit 7 - 1):保留位,必须设置为 0.
    • Session Present (Bit 0):用于指示服务端是否正在使用已存在的会话与客户端恢复通信。仅在客户端在 CONNECT 连接中将 Clean Start 设置为 0 时,Session Present 可能为 1。
  • Reason Code:用于指示连接结果。下表列出了一些在 CONNACK 报文中常见的 Reason Code,完整列表可参阅 MQTT 5.0 Reason Code 速查表。

Value

Reason Code Name

Description

0x00

Success

连接被接受。

0x81

Malformed Packet

服务端无法按照协议规范正确解析 CONNECT 报文,例如保留位没有按照协议要求设置为 0。

0x82

Protocol Error

CONNECT 报文可以被正确解析,但是内容不符合协议规范,比如 Will Topic 字段的值不是一个合法的 MQTT 主题。

0x84

Unsupported Protocol Version

服务端不支持客户端所请求的 MQTT 协议版本。

0x85

Client Identifier not valid

表示 Client ID 是有效的字符串,但是不被服务端接受,比如 Client ID 超出了服务端允许的最大长度。

0x86

Bad User Name or Password

客户端因为使用了错误的用户名或密码而被拒绝连接。

0x95

Packet too large

CONNECT 报文超过了服务端允许的最大长度,可能是因为携带了较大的遗嘱消息。

0x8A

Banned

表示客户端被禁止登录。例如服务端检测到客户端的异常连接行为,所以将这个客户端的 Client ID 或者 IP 地址加入到了黑名单列表中,又或者是后台管理人员手动封禁了这个客户端,当然以上这些通常需要视服务端的具体实现而定。

  • Properties:下表列出了 CONNACK 报文的所有可用属性。

Identifier

Property Name

Type

0x11

Session Expiry Interval

四字节整数

0x21

Receive Maximum

双字节整数

0x24

Maximum QoS

单字节

0x25

Retain Available

单字节

0x27

Maximum Packet Size

四字节整数

0x12

Assigned Client Identifier

UTF-8 编码的字符串

0x22

Topic Alias Maximum

双字节整数

0x1F

Reason String

UTF-8 编码的字符串

0x26

User Property

UTF-8 字符串对

0x28

Wildcard Subscription Available

单字节

0x29

Subscription Identifier Available

单字节

0x2A

Shared Subscription Available

单字节

0x13

Server Keep Alive

双字节整数

0x1A

Response Information

UTF-8 编码的字符串

0x1C

Server Reference

UTF-8 编码的字符串

0x15

Authentication Method

UTF-8 编码的字符串

0x16

Authentication Data

二进制数据

有效载荷

CONNACK 报文不包含有效载荷。

总结

CONNECT 是客户端与服务端的网络连接建立后,客户端发送的第一个 MQTT 报文,CONNACK 作为 CONNECT 的响应报文通过原因码来指示连接结果。

客户端和服务端需要借助 CONNECT 和 CONNACK 报文来完成必要信息的交换,例如客户端使用的协议版本、Client ID、用户名、密码,以及服务端是否存在相应的会话、支持的最大报文长度和最大 QoS 等级等等。

以上就是对 MQTT CONNECT 和 CONNACK 报文的介绍,在后续的文章中,我们还会继续研究 PUBLISH、DISCONNECT 这些报文的结构和组成。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 报文示例
  • CONNECT 报文结构
    • 固定报头
      • 可变报头
        • 有效载荷
        • CONNACK 报文结构
          • 固定报文
            • 可变报头
              • 有效载荷
              • 总结
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档