**连接** **MQTT** 服务端
连接 MQTT 服务端
首先客户端需要向服务端发送连接请求,这个连接请求实际上就是向服务端发送一个 CONNECT报文,也就是发送了一个 CONNECT 数据包


MQTT 服务端收到连接请求后,会向客户端发送连接确认。连接确认实际上是向客户端发送一个CONNACK 报文,也就是 CONNACK 数据包
MQTT报文结构
1. 固定头(Fixed Header)
每个MQTT报文都包含一个固定头,其结构如下:
| 比特 | 7-4 | 3-0 |
|---|---|---|
| 字节1 | 报文类型 | 标志位 |
| 字节2 | 剩余长度 |
- 报文类型:CONNECT报文的类型值为1,所以字节1的高4位为0x1。
- 标志位:对于CONNECT报文,固定头的低4位是保留的,必须设置为0。所以整个固定头的第一个字节是0x10。
- 剩余长度:表示可变头和有效载荷的总长度。这个字段使用变长编码,最多4个字节。
2. 可变头(Variable Header)
CONNECT报文的可变头按顺序包含以下内容:
- 协议名(Protocol Name):是一个UTF-8编码的字符串。对于MQTT 3.1.1,协议名为"MQTT",长度为4,所以先写两字节的长度0x00,0x04,然后写'M','Q','T','T'。
- 协议级别(Protocol Level):对于MQTT 3.1.1,这个值为4,即0x04。
- 连接标志(Connect Flags):一个字节,包含多个标志,如下:
| 比特 | 标志 | 描述 |
|---|---|---|
| 7 | User Name | 为1表示有效载荷中包含用户名 |
| 6 | Password | 为1表示有效载荷中包含密码 |
| 5 | Will Retain | 遗嘱保留标志 |
| 4-3 | Will QoS | 遗嘱QoS等级 |
| 2 | Will Flag | 为1表示有效载荷中包含遗嘱 |
| 1 | Clean Session | 清理会话标志 |
| 0 | 保留 | 必须为0 |
- 保持连接(Keep Alive):两个字节,表示客户端传输控制报文的最大时间间隔(秒)。图中为60,即0x00,0x3C。
3. 有效载荷(Payload)
CONNECT报文的有效载荷包含一个或多个以UTF-8编码的字符串,具体包括:
- 客户端标识符(Client ID):必须存在,除非客户端标识符长度为0且清理会话为0(不允许),但通常都会有。
- 遗嘱主题(Will Topic):如果遗嘱标志为1,则存在。
- 遗嘱消息(Will Message):如果遗嘱标志为1,则存在。
- 用户名(User Name):如果用户名标志为1,则存在。
- 密码(Password):如果密码标志为1,则存在。
每个字符串的前面是两个字节的长度(MSB, LSB),然后是对应长度的UTF-8字符串。
CONNECT报文

如果不符合MQTT规范,服务器会拒绝连接
固定头:不包括表格中列出的任何字段,固定头是固定的格式,用于标识报文类型和剩余长度。
可变头:包括keepAlive、cleanSession(以及willRetain、willQos,这些是连接标志的一部分)等字段。
有效载荷:包括clientID、willTopic、willMessage、username、password等字段。
clientID-客户端 id
clientId 是 MQTT 客户端的标识,也就是 MQTT 客户端的名字,MQTT 服务端可通过 clientId 来区分不
同的客户端,MQTT 服务端用该标识来识别客户端。
如果两个 MQTT 客户端使用相同 clientId 标识,服务端会把它们当成同一个客户端来处理。
keepAlive--心跳时间间隔
客户端在没有向服务端发送信息时(空闲时),可以定时向服务端发送一个心跳数据包,这个心跳包也被称作心跳
请求,心跳请求的作用正是用于告知服务端,当前客户端依然在线,服务端在收到客户端的心跳请求后,会回复一条消息,这条回复消息被称作心跳响应。
譬如 keepAlive=60,表示告诉
服务端,客户端将会每隔 60 秒左右向服务端发送心跳包。
cleanSession--清除会话
它是一个布尔值,如果连接服务端时 cleanSession=0,当 MQTT 客户端由离线(与服务端断开连接)再次上线时,离线期间发给客户端的所有 QoS>0 的消息仍然可以接收到;
如果连接服务端时 cleanSession=1,当 MQTT 客户端由离线(与服务端断开连接)再次上线时,离线期间发给客户端的所有消息一律接收不到。
假设当前你的 QQ 账号没有登录或者说当前处于离线状态,与服务器断开了连接;而在离线期间,你的 QQ 好友给你发了几条信息;由于当前你的 QQ 处于离线状态,自然是接收不到好友发送过来的信息,但是,当你的 QQ 恢复连接状态时,立马会接收到好友在离线期间所发给你的信息。
总的来说:cleanSession 设置为 1,表示此次连接将创建一个新的临时会话,在客户端断开后,这个会话会自动销毁。而 cleanSession 设置为 0,表示创建一个持久性会话,在客户端断开连接时,会话仍然保持并保存离线消息,直到会话超时注销。
CONNACK报文

returnCode--连接返回码
当服务端收到了客户端(esp8266)的连接请求后,会向客户端发送 returnCode(连接返回码),用来说明连接情况。

sessionPresent
在 cleanSession=0 的情况下,当客户端连接到服务器之后,可通过 CONNACK 报文中返回的
sessionPresent 来查询服务端是否为客户端保存了会话状态(客户端上一次连接时的会话状态信息),如果
服务端已为客户端保存了上一次连接时的会话状态,则 sessionPresent=1,如果没有保存会话状态,则
sessionPresent=0。
如果 cleanSession=1,在这种情况下,客户端是不需要服务端保存会话状态的,那么服务端发送的确认
连接 CONNACK 报文中,sessionPresent 肯定是 false(sessionPresent=0),也就是说,服务端没有保存客户端的会话状态信息。
简言之,CONNACK 报文的 sessionPresent 与 CONNECT 报文的 cleanSession 相互配合。

