第 3 章 · 02 CONNACK:确认连接请求 本节摘要:CONNACK 是服务端对 CONNECT 的答复,也是服务端发给客户端的第一条报文 [MQTT-3.2.0-1]。它只有 4 个字节:固定报头 2 字节 + 可变报头 2 字节,没有有效载荷。两个字节各干一件事:连接确认标志里的当前会话位告诉客户端"你的旧会话还在不在",连接返回码告诉客户端"你被接受还是被拒绝"。本节把 6 种返回码和当前会话标志的三种判定讲透。 学习目标 阅读完本节,你应当能够: 默写 CONNACK 的报文结构(固定报头 0x20 0x02 + 2 字节可变报头)。 解释当前会话标志在三种情形下的取值规则。 背出 6 种连接返回码(0x000x05)及各自触发场景。
本节摘要:CONNACK 是服务端对 CONNECT 的答复,也是服务端发给客户端的第一条报文 [MQTT-3.2.0-1]。它只有 4 个字节:固定报头 2 字节 + 可变报头 2 字节,没有有效载荷。两个字节各干一件事:连接确认标志里的当前会话位告诉客户端"你的旧会话还在不在",连接返回码告诉客户端"你被接受还是被拒绝"。本节把 6 种返回码和当前会话标志的三种判定讲透。
阅读完本节,你应当能够:
| 段 | 内容 |
|---|---|
| 固定报头 | 首字节 0x20(类型 2 + 标志 0000),剩余长度 = 2 |
| 可变报头字节 1 | 连接确认标志:位 7~1 保留必须为 0;位 0 是当前会话(Session Present) 标志 |
| 可变报头字节 2 | 连接返回码(1 字节无符号值) |
服务端发送非零返回码的 CONNACK 后,必须关闭网络连接 [MQTT-3.2.2-5]。如果所有返回码都不合适,服务端直接关闭连接、不发 CONNACK [MQTT-3.2.2-6]。
当前会话标志让客户端与服务端对"是否存在已保存的会话状态"达成一致:
| 情形 | 当前会话标志 |
|---|---|
| 客户端用清理会话=1 连接 | 必须为 0(旧的都丢弃了,谈何会话) [MQTT-3.2.2-1] |
| 清理会话=0,服务端有该 ClientId 的已保存会话 | 必须为 1 [MQTT-3.2.2-2] |
| 清理会话=0,服务端没有已保存会话 | 必须为 0,且返回码为 0 [MQTT-3.2.2-3] |
| CONNACK 携带非零返回码 | 必须为 0 [MQTT-3.2.2-4] |
⚠️ 一个常见实现 bug:清理会话=0 首次连接时,服务端刚建好新会话,但当前会话标志必须填 0(表示"没有恢复旧状态"),不是 1。
💡 客户端视角:若当前会话标志与预期不符(比如客户端以为会话还在,服务端说没有),客户端可以继续,也可以主动"清场重来"——断开 → 清理会话=1 重连 → 再断开,丢弃两侧状态。
| 值 | 含义 | 典型触发场景 |
|---|---|---|
| 0x00 | 连接已接受 | 一切正常 |
| 0x01 | 不支持的协议版本 | 客户端协议级别不是服务端支持的值 |
| 0x02 | 不合格的客户端标识符 | ClientId 是正确的 UTF-8 但服务端不允许(如零 ClientId 配清理会话=0) |
| 0x03 | 服务端不可用 | 网络已建立,但 MQTT 服务不可用 |
| 0x04 | 无效的用户名或密码 | 认证凭据格式/内容错误 |
| 0x05 | 未授权 | 客户端未被授权连接 |
| 0x06~0xFF | 保留 | 不得使用 |
💡 返回码是"业务裁决"与"协议错误"的分界线:协议格式错误(如非法标志位)走"直接断开、无确认"路线;而格式合法但语义不被接受的请求才用返回码答复。0x02 就是典型:ClientId 本身编码合法,只是策略不允许。
CONNACK 用 2 个字节回答了 CONNECT 的所有请求:当前会话位对齐会话状态,返回码裁决连接命运。连接成功后,客户端就可以自由发布与订阅了——下一节看承载业务数据的 PUBLISH。