【MQTT从入门到提高系列 | 04】MQTT应用协议之CONNECT与CONNACK

这是机器未来的第29篇文章

原文首发地址:http://t.csdn.cn/7Degv

mqtt_sologon

1. 概述

本文描述了MQTT应用协议中的Connect和ConnAck命令的细节。

2. CONNECT – 客户端请求连接到服务器

在客户端与服务器建立网络连接后,从客户端发送到服务器的第一个数据包必须是 CONNECT 数据包 [MQTT-3.1.0-1]。

客户端只能通过网络连接发送一次 CONNECT 数据包。服务器必须处理从客户端发送的第二个 CONNECT 数据包作为协议违规并断开客户端 [MQTT-3.1.0-2]。有关处理错误的信息,请参阅第 4.8 节。

有效载荷包含一个或多个编码字段。他们为客户指定唯一的客户标识符、遗嘱主题、遗嘱消息、用户名和密码。除客户端标识符外,所有标识符都是可选的,它们的存在是根据变量标头中的标志确定的。

2.1 协议报文头定义

14

2.1.1 Fixed Header-固定报文头

MQTT控制包类型为0x01, 对应CONNECT命令

2.1.2 ProtocolName-协议名称

  • 数据编码格式为2字节长度+Data,其值固定为"\x00\x04MQTT"。
  • 如果协议名称不正确,服务器可能会断开客户端,或者它可能会根据其他规范继续处理 CONNECT 数据包。在后一种情况下,服务器不得继续按照本规范 [MQTT-3.1.2-1]处理 CONNECT 数据包。
  • 包检查器(例如防火墙)可以使用协议名称来识别 MQTT 流量。

2.1.3 ProtocolLevel

  • 8 位无符号值,表示客户端使用的协议的修订级别。协议版本 3.1.1 的协议级别字段的值为 4 (0x04)
  • 如果服务器不支持协议级别 [MQTT-3.1.2-2] ,必须以 CONNACK 返回码 0x01(不可接受的协议级别)响应 CONNECT 数据包,然后断开客户端。

2.1.4 ConnectFlags - 连接标志

2.1.4.1 CleanSession-清洁会话

该位指定会话状态的处理。 客户端和服务器可以存储会话状态,以使可靠的消息传递在一系列网络连接中继续。该位用于控制 Session 状态的生命周期。

  • CleanSession为0时,链路断开后,服务器仍然会保存会话状态,下一次重新连接时,服务器会恢复会话,并发布断开前存储的QoS1、QoS2消息;

  • CleanSession为1时,链路断开后,服务器会丢弃会话状态,下一次重新连接时,也不会继承之前的会话,服务器会重新创建一个新的会话。

  • 通常,客户端将始终使用设置为 0 的 CleanSession 或设置为 1 的 CleanSession 进行连接,并且不会在两个值之间交换。使用 CleanSession 设置为 1 的客户端将不会收到旧的应用程序消息,并且每次连接时都必须重新订阅它感兴趣的任何主题。使用 CleanSession 设置为 0 的客户端将接收在断开连接时发布的所有 QoS 1 或 QoS 2 消息。因此,为确保在断开连接时不会丢失消息,请使用 QoS 1 或 QoS 2 并将 CleanSession 设置为 0

  • Clean Session为0的会话退出机制:当客户端连接 CleanSession 设置为 0 时,它请求服务器在断开连接后保持其 MQTT 会话状态。如果客户端打算在稍后的某个时间点重新连接到服务器,则客户端应仅将 CleanSession 设置为 0 进行连接。当客户端确定它不再使用会话时,它应该进行最终连接,并将 CleanSession 设置为 1,然后断开连接。

  • 会话状态包含的内容:

    • Client 中的 Session 状态包括:

      • QoS 1 和 QoS 2 消息已发送到服务器,但尚未完全确认。
      • 已从服务器收到但尚未完全确认的 QoS 2 消息。
    • 服务器中的会话状态包括:

      • 一个Session的存在,即使Session的其余状态为空。

      • 客户的订阅。

      • QoS 1 和 QoS 2 消息已发送到客户端,但尚未完全确认。

      • QoS 1 和 QoS 2 消息等待传输到客户端。

      • 已从客户端收到但尚未完全确认的 QoS 2 消息。

      • 可选地,QoS 0 消息等待传输到客户端。

        保留的消息不构成服务器中会话状态的一部分,它们不能在会话结束时被删除

2.1.4.2 WillFlag-遗言标志

  • Will Flag=1,Connect请求被接收后,如果异常断开,则发布遗言;如果客户端发送DISCONNET到服务器正常关闭,服务器会删除遗言,不予发布。Will Flag=1时,Connect Flags 中的Will Qos和Will Retain必须配置,且 Will Topic 和 Will Message 字段必须存在于有效负载中。

  • Will Flag=0,Connect Flags 中的 Will QoS 和 Will Retain 字段必须设置为零,并且 Will Topic 和 Will Message 字段不得出现在有效负载中 [MQTT-3.1.2-11] 。

遗嘱信息发布的情况包括但不限于:

  • 服务器检测到 I/O 错误或网络故障。
  • 客户端无法在 Keep Alive 时间内进行通信。
  • 客户端关闭网络连接而不首先发送 DISCONNECT 数据包。
  • 由于协议错误,服务器关闭了网络连接。

2.1.4.3 WillQoS-遗言QoS

占2个bit,指定发布遗嘱消息时要使用的 QoS 级别

  • Will Flag=0,WillQoS必须置0
  • Will Flag=1,WillQoS可以配置为0,1,2,遵照QoS的应用逻辑。

2…1.4.4 WillRetain-遗言保留标志

指定遗嘱消息在发布时是否要保留。

  • Will Flag=0,WillRetain必须置0
  • Will Flag=1,WillRetain可以配置为0,1
    • Will Retain = 0,服务器必须将 Will Message 作为非保留消息发布
    • Will Retain = 1,服务器必须将 Will Message 作为保留消息发布

2.1.4.5 UserNameFlag-用户名标志

  • UserNameFlag= 0,则用户名不得出现在有效负载 [MQTT-3.1.2-18]中。
  • UserNameFlag=1,则用户名必须存在于有效负载 [MQTT-3.1.2-19]中。

2.1.4.6 PasswordFlag-密码标志

  • UserNameFlag=0,则PasswordFlag必须为0;
  • UserNameFlag=1:
    • PasswordFlag=0,则有效负载中不得存在密码 [MQTT-3.1.2-20]。
    • PasswordFlag=1,则有效负载中必须存在密码 [MQTT-3.1.2-21]。

2.1.4.7 KeepAlive-保活标志

KeepAlive占用2个字节,高位在前,低位在后,它是客户端完成发送一个控制数据包的点和它开始发送下一个控制包的点之间允许经过的最大时间间隔。

客户端有责任确保发送控制包之间的时间间隔不超过 Keep Alive 值。在没有发送任何其他控制数据包的情况下,客户端必须发送一个 PINGREQ 数据包 [MQTT-3.1.2-23]。

  • 保活链路断开逻辑
    • 如果 Keep Alive 值非零,并且服务器在 Keep Alive 时间段的一倍半内没有收到来自客户端的控制数据包,它必须断开与客户端的网络连接,就好像网络发生故障一样 [MQTT -3.1.2-24] 。

    • 如果客户端在发送 PINGREQ 后的合理时间内没有收到 PINGRESP 数据包,它应该关闭与服务器的网络连接。

KeepAlive的值由实际应用决定,一般配置为几分钟,最大可配置为 18 小时 12 分 15 秒

2.2 协议报文负载定义

15负载包含一个或多个以长度为前缀的字段,其存在由可变头中的标志确定。这些字段(如果存在)必须按客户端标识符、遗嘱主题、遗嘱消息、用户名、密码[MQTT-3.1.3-1] 的顺序出现。

2.2.1 Client Identifier客户端标识符

  • 客户端标识符必须存在,且在服务器唯一,且需要符合UTF-8编码字符串格式,其长度范围为1~23Bytes,且必须在“0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ”字符范围内取值
  • 如果服务器拒绝 ClientId,它必须以 CONNACK 返回码 0x02(标识符被拒绝)响应 CONNECT 数据包,然后关闭网络连接

2.2.2 Will Topic遗言主题

如果WillFlag设置为 1,则遗嘱主题必须包含在负载中。遗嘱主题必须是第1.5.3节 [MQTT-3.1.3-10]中定义的 UTF-8 编码字符串。

2.2.3 Will Message遗言消息

如果WillFlag设置为 1,则遗嘱消息必须包含在负载中,数据与不必符合UTF-8编码字符串的要求,二进制编码

2.2.4 UserName用户名

UserNameFlag=1时包含该字段,用户名必须是第1.5.3节 [MQTT-3.1.3-11]中定义的 UTF-8 编码字符串。 服务器可以使用它进行身份验证和授权

2.2.4 Password密码

PasswordFlag=1时包含该字段,密码字段包含 0 到 65535 字节的二进制数据,前缀为两字节长度字段,指示二进制数据使用的字节数(不包括长度字段本身占用的两个字节)

2.3 服务端响应逻辑

如果服务器确定协议是 MQTT 3.1.1,则它验证连接尝试如下:

  • 如果服务器在网络连接建立后的合理时间内没有收到 CONNECT 数据包,服务器应该关闭连接

  • 服务器必须验证 CONNECT 数据包格式符合第3.1节,如果不符合[MQTT-3.1.4-1]则关闭网络连接而不发送 CONNACK 。

  • 服务器可以检查 CONNECT 数据包的内容是否满足任何进一步的限制,并且可以执行身份验证和授权检查。如果这些检查中的任何一个失败,它应该发送一个适当的 CONNACK 响应,它必须关闭网络连接。

如果验证成功,服务器将执行以下步骤:

  • 如果 ClientId 代表一个已经连接到服务器的客户端,那么服务器必须断开现有的客户端
  • 服务器必须执行 CleanSession 处理。
  • 服务器必须使用包含零返回码的 CONNACK 数据包来确认 CONNECT 数据包。
  • 启动消息传递和存活监控。

流程简化:

  • 允许客户端在发送 CONNECT 数据包后立即发送进一步的控制数据包;客户端无需等待来自服务器的 CONNACK 数据包到达。如果服务器拒绝 CONNECT,它绝不能处理客户端在 CONNECT 数据包之后发送的任何数据。

  • 客户端通常等待 CONNACK 数据包,但是,如果客户端利用其在收到 CONNACK 之前发送控制数据包的自由,它可能会简化客户端实现,因为它不必监管连接状态。如果服务器拒绝连接,客户端接受它在从服务器接收到 CONNACK 数据包之前发送的任何数据都不会被处理。

3. CONNACK – 连接确认

CONNACK 数据包是服务器响应从客户端接收到的 CONNECT 数据包而发送的数据包。从服务器发送到客户端的第一个数据包必须是一个 CONNACK 数据包。

客户端断开链路逻辑:
如果客户端在合理的时间内没有收到来自服务器的 CONNACK 数据包,客户端应该关闭网络连接。“合理”的时间量取决于应用程序的类型和通信基础设施。

16

3.1 Connect Acknowledge Flags连接确认标志

Bit0的SP(Session Present - 会话存在标志),Session Present 标志使客户端能够确定客户端和服务器是否具有关于是否已经存储会话状态的一致视图,其使用逻辑为:
- CleanSession ==1, 且服务器接收客户端(即Connect Return Code=0),则服务器需要将SP置为0
- CleanSession ==0, 且服务器接收客户端(即Connect Return Code=0),如果服务器存储了ClientID对应的会话,则服务器将SP置1;否则置0。
- 如果服务器发送包含非零返回码的 CONNACK 数据包(Connect Return Code!=0),它必须将 Session Present 设置为0

如果 Client 从 Server 收到的 Session Present 的值不符合预期,Client 可以选择是继续 Session 还是断开连接。客户端可以通过断开连接来丢弃客户端和服务器上的会话状态,操作步骤:将 Clean Session 设置为 1 进行连接,然后再次断开连接。

3.2 Connect Return Code连接返回码

如果服务器接收到一个格式良好的 CONNECT 数据包,但由于某种原因服务器无法处理它,那么服务器应该尝试发送一个包含此表中适当的非零连接返回代码的 CONNACK 数据包,并关闭网络连接

17

3.3 负载

《MQTT快速入门系列》快速导航:

写在末尾:

  • 博客简介:专注AIoT领域,追逐未来时代的脉搏,记录路途中的技术成长!
  • 专栏简介:从0到1掌握MQTT分布式协议。
  • 面向人群:零基础编程爱好者
  • 专栏计划:接下来会逐步发布跨入人工智能的系列博文,敬请期待

猜你喜欢

转载自blog.csdn.net/RobotFutures/article/details/125724750