【IM即时通讯】MQTT协议的详解(2)- CONNECT Packet
前言
关于所有的类型的数据示例已经在上面一篇博客说完:
【IM即时通讯】MQTT协议的详解回顾的同学可以直达这里
说明
CONNECT Packet
此包是客户端与服务端建立连接后,发送的第一个包,且第一个包必须是此包。在一个连接中,该包只能发送一次。若发送了多次,当服务器第二次收到该包时,应该作为违法处理,立即断开连接。
一、固定同步详解、可变头部详解
- 固定头部
+---------------------------------------------------------+
| bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+---------------------------------------------------------+
| byte1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
+---------------------------------------------------------+
| byte2...| Remaining Length |
+---------------------------------------------------------+
- 可变头部
+--------+----------------+---+---+---+---+---+---+---+---+
| Bit | Description | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+---------------------------------------------------------+
| byte 1 | Length MSB (0)| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+---------------------------------------------------------+
| byte 2 | Length LSB (4)| 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+---------------------------------------------------------+
| byte 3 | 'M' | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 |
+---------------------------------------------------------+
| byte 4 | 'Q' | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 1 |
+---------------------------------------------------------+
| byte 5 | 'T' | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 |
+---------------------------------------------------------+
| byte 6 | 'T' | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 0 |
+---------------------------------------------------------+
| byte 7 | Level(4) | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
+---------------------------------------------------------+
| byte 8 | x | x | x | x | x | x | x | x | 0 |
+--------+----------------+---+---+---+---+---+---+---+---+
| byte 9 | Keep Alive MSB |
+---------------------------------------------------------+
| byte 10| Keep Alive LSB |
+--------+----------------+---+---+---+---+---+---+---+---+
其中,
- 如前面介绍,前 2 个字节是包 ID。
- 3 ~ 6 字节是协议名称,字符使用 UTF-8 编码;
- 第 7 个字节是协议等级(协议版本。3.1.1 版本对应的协议等级是 4
- 第8个字节包含一些连接标记位。如下图所示:
Bit | Description |
---|---|
7 | 是否有用户名字标志位英文:【User Name Flag】 |
6 | 是否有密码标志位 英文:【Password Flag】 |
5 | 决定遗嘱消息是否被服务器保留英文:【Will Retain】 |
4~3 | 决定遗嘱消息的服务质量等级 英文:【Will QoS】 |
2 | 指示是否有遗嘱消息需要在连接断开时发布 英文:【Will Flag】 |
1 | 决定是否清除之前的会话信息 英文:【Clear session】 |
0 | 保留位,必须设置为0 (也有可能不为0)英文:【Reserved】 |
注意
:
若服务端不支持客户端协议版本,需要响应一个 CONNACK 包,指定 code 为 0x01,然后断开连接.服务端需校验 Reserved 位。若值不为 0,需断开连接。
-
Clear session:用来指定对 Session 的处理方式。若值为0,在服务端和客户端断开连接后,它们都要保存 Session 信息,以便再次连上时恢复之前 Session 中的信息。除此之外,服务端还需要在断开连接后保存 QoS 1 和 QoS 2 消息和客户端的订阅内容;若值为1,当客户端和服务端连接上时,必须丢弃之前的 Session 状态信息再创建一个新的 Session 和订阅内容。
-
位置:连接标识字节的第1位(Bit 1)
-
在客户端,Session 状态信息包括:
已被发送到服务端,但还没有被确认的 QoS 1 和 QoS 2 消息;
已被服务器接收,但还没有被确认的 QoS 2 消息。
在服务端,Session 状态信息包括: -
客户端的订阅内容;
已被发送到服务端,但还没有被确认的 QoS 1 和 QoS 2 消息;
待发送到客户端的QoS 1 和 QoS 2 消息;
已被客户端接收,但还没有被确认的QoS 2 消息;
(可选)待发送到客户端的QoS 0 消息;
-
-
Will Flag,Will QoS,Will Retain:这三个字段是用来预立“遗嘱”的。预立“遗嘱”的意思是:客户端在连接服务端时,可将预先定义好的主题和对应消息发送给服务端。当它和服务端连接断开时,服务端将及时地发布这段消息到预定的主题。
- Will Flag:
位置:连接标识字节的第2位(Bit 2)
含义:此标志位指示客户端是否指定了一个遗嘱(Will)消息。如果Will Flag 被设置为1,表明客户端希望在连接意外断开时,服务器能够发布一个预定义的遗嘱消息到指定的遗嘱主题。如果设置为0,则没有遗嘱消息被指定。 - Will QoS (遗嘱服务质量);
位置:连接标识字节的第3和第4位(Bit 3 和 Bit 4)
含义:这两个位共同表示遗嘱消息的服务质量(QoS)。QoS 级别可以是0(最多一次交付),1(至少一次交付),或2(恰好一次交付)。只有当Will Flag 被设置为1时,这两个位才有效。 - Will Retain:
位置:连接标识字节的第5位(Bit 5)
含义:此标志位决定遗嘱消息是否被服务器保留。如果Will Retain 被设置为1,服务器将保留遗嘱消息,并将其作为新订阅者的默认消息。如果设置为0,遗嘱消息将不会被服务器保留。
- Will Flag:
-
Password Flag:表示客户端将提供密码进行认证。如果设置为0,则不包含密码信息。
- 位置:连接标识字节的第6位(Bit 6)
含义:此标志位指示是否在CONNECT Packet 的载荷中包含密码信息。如果Password Flag 被设置为1
- 位置:连接标识字节的第6位(Bit 6)
-
User Name Flag:此标志位指示是否在CONNECT Packet 的载荷中包含用户名信息。
- 位置:连接标识字节的第7位(Bit 7)
- 如果User Name Flag 被设置为1,表示客户端将提供用户名进行认证。如果设置为0,则不包含用户名信息。
二、载荷内容详解
CONNECT 包的载荷一定包含 Client Identifier 字段,可能包含 Will Topic, Will Message, User Name, Password 字段(由可变头部中的各标记位决定)。这些字段若存在,一定要按照以上顺序排列。
- Client Identifier:由客户端自己指定的 ID,服务端据此来标识客户端(以此关联Session)。因此不同客户端之间的 ID 不能重复(重复将视为同一客户端)。它使用 UTF-8编码,长度通常在1 ~ 23个字节之间,通常包含 [0-9a-zA-Z] 中的字符(允许例外,由服务端的实现决定)。若客户端 ID 不存在,服务端需要为其指定一个独一无二的 ID。在这种情况下,客户端必须设置 CleanSession 为 1;若不设为 1,服务端需要 响应 CONNACK 包,其中 返回 code 0x02(Identifier rejected), 随后断开连接。
- Will Topic,Will Message:当 Will Flag 值为 1 时存在,均采用 UTF-8 编码。
- User Name:采用 UTF-8 编码,用来做身份认证。
- Password:长度不固定,头两个字节用来指明密码的字节数,之后是密码的字节,结构如下:
+-----------+---+---+---+---+---+---+---+---+
| Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+---------------+---+---+---+---+---+---+---+
| byte 1 | Data length MSB |
+-------------------------------------------+
| byte 2 | Data length LSB |
+-------------------------------------------+
| byte 3...| Data, if length > 0. |
+-------------------------------------------+
在 MQTT 协议中,字符串均采用的 UTF-8 编码
+------------------------------------------------------------+
| Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+------------------------------------------------------------+
| byte1 | String length MSB |
+------------------------------------------------------------+
| byte2 | String length LSB |
+------------------------------------------------------------+
| byte3...| UTF-8 Encoded Character Data, if length > 0 |
+------------------------------------------------------------+
一些情况的处理方式:
注意:在一个客户端在线的情况下,同一客户端(相同 Client ID)再次连接服务端,服务端需断开之前的连接;客户端在发送 CONNECT 包后,可以再立即发送其他的包,而无需等待 CONNACK 包的响应。但服务端收到 CONNECT 包后,若拒绝连接,一定不能处理客户端在 CONNECT 包后发送的包。
总结
下一个类型:CONNACK Packet