MQTT 控制报文简介
插图:© IoT For All --> MQTT 控制数据包是 MQTT 中数据传输的最小单位。MQTT 客户端和服务器通过交换控制数据包来执行各种任务,例如订阅主题和发布消息。目前,MQTT 定义了 15 种类型的控制数据包。如果我们根据其功能对它们进行分类,可以将这些数据包分为三类:连接、发布和订阅。EMQ Technologies 其中,CONNECT 数据包用于客户端发起与服务器的连接,CONNACK 数据包作为响应,用于指示连接结果。如果希望终止通信或遇到需要断开连接的错误,客户端和服务器可以发送 DISCONNECT 数据包,然后关闭网络连接。AUTH 数据包是 MQTT 5.0 引入的新类型数据包,专门用于增强认证,为客户端和服务器提供更安全的认证方式。PINGREQ 和 PINGRESP 数据包用于连接保活和探测。客户端定期发送 PINGREQ 数据包到服务器,表示自己仍然活跃,并根据服务器是否及时返回 PINGRESP 数据包判断服务器是否活跃。PUBLISH 数据包用于发布消息,其余四个数据包用于确认 QoS 1 和 QoS 2 消息。SUBSCRIBE 数据包用于客户端订阅主题,UNSUBSCRIBE 数据包则用于取消订阅。SUBACK 和 UNSUBACK 数据包分别用于返回订阅和取消订阅的结果。MQTT 数据包格式 在 MQTT 中,无论控制数据包的类型如何,它们都由三个部分组成:固定头(Fixed Header)、可变头(Variable Header)和负载(Payload)。固定头在所有控制数据包中始终存在。可变头和负载的存在与否及其内容则取决于具体的数据包类型。例如,用于保活的 PINGREQ 数据包仅包含固定头,而用于传输应用消息的 PUBLISH 数据包则包含全部三个部分。EMQ Technologies 固定头 固定头由三个字段组成:MQTT 控制数据包类型、标志(Flags)和剩余长度(Remaining Length)。EMQ Technologies MQTT 控制数据包类型位于固定头第一个字节的高 4 位中。它是一个无符号整数,表示当前数据包的类型。例如,1 表示 CONNECT 数据包,2 表示 CONNACK 数据包,依此类推。详细的映射关系可以参考《MQTT 5.0 规范 – MQTT 控制数据包类型》。实际上,除了 MQTT 控制数据包类型和剩余长度字段外,其余部分的内容取决于具体的包类型。因此,该字段决定了接收方如何解析数据包的后续内容。固定头第一个字节的低 4 位包含由控制数据包类型决定的标志位。然而,截至 MQTT 5.0,只有 PUBLISH 数据包中的这四个位具有特定含义:第 3 位:DUP,表示当前的 PUBLISH 数据包是否为重传数据包。第 2、1 位 QoS,表示当前的 PUBLISH 数据包所使用的服务质量等级。第 0 位:Retain,表示当前的 PUBLISH 数据包是否为保留消息。在所有其他数据包类型中,这 4 位是预留的,意味着它们具有固定值,不能随意更改。最后的剩余长度字段表示控制数据包剩余部分的字节数,其中包括可变头和负载。因此,MQTT 控制数据包的总长度等于固定头的长度加上剩余长度。EMQ Technologies 可变字节整数 然而,固定头的长度并不是固定的。为了尽可能减小数据包的大小,MQTT 使用剩余长度字段作为可变字节整数。在 MQTT 中,有很多字段的长度是可变的。例如,PUBLISH 数据包中的负载部分用于承载实际的应用消息,而应用消息的长度并不固定。因此,我们需要一个额外字段来指示这些可变长度内容的长度,以便接收端能够正确解析它们。对于一个总长度为 2,097,152 字节(即 2MB)的应用消息,我们需要一个 4 字节的整数来指示其长度。然而,并非所有应用消息都如此庞大;在许多情况下,它们仅是几 KB,甚至只有几个字节。用 4 字节的整数来指示一个长度仅为 2 字节的消息显然过于浪费。因此,MQTT 引入了可变字节整数,利用每个字节的低 7 位来编码数据,而最高位则指示是否还有后续字节。这样一来,当数据包长度小于 128 字节时,可变字节整数只需要一个字节即可表示。可变字节整数的最大长度为 4 字节,可以表示最多 (2^28 – 1) 字节,即 256MB 的数据。EMQ Technologies 可变头 MQTT 中的可变头内容取决于具体的包类型。例如,CONNECT 数据包的可变头依次包括协议名称、协议级别、连接标志、保活时间和属性。PUBLISH 数据包的可变头依次包括主题名、包标识符(如果 QoS 不为 0)和属性。EMQ Technologies 可变头中的字段必须严格按照协议规范排列,因为接收方只能按照指定的顺序解析它们。除非协议明确要求或允许,否则不能省略任何字段。例如,在 CONNECT 数据包的可变头中,若连接标志紧跟在协议名称之后,会导致解析失败。同样,在 PUBLISH 数据包的可变头中,只有在 QoS 不为 0 时,包标识符才会出现。属性 属性是 MQTT 5.0 引入的一个概念,是可变头的最后部分。属性由属性长度字段后接一组属性组成。属性长度字段用于指示后续所有属性的总长度。EMQ Technologies 所有属性都是可选的,因为它们通常具有默认值。如果没有属性,则属性长度字段的值为 0。每个属性由一个定义其用途和数据类型的标识符和一个具体值组成。不同的属性可能有不同的数据类型。例如,一个是两字节的整数,另一个是 UTF-8 编码的字符串,因此我们需要根据标识符声明的数据类型来解析属性。EMQ Technologies 属性的顺序可以是任意的,因为我们可以通过标识符知道属性的种类及其长度。属性通常是为了特定用途设计的。例如,CONNECT 数据包有一个 Session Expiry Interval 属性,用于设置会话的过期时间。然而,这个属性在 PUBLISH 数据包中并不需要。因此,MQTT 对属性的使用范围有严格定义,有效的 MQTT 控制数据包不应包含不属于它的属性。关于 MQTT 属性的完整列表,包括其标识符、属性名称、数据类型和使用范围,请参考《MQTT 5.0 规范 – 属性》。负载 最后,我们来看负载部分。数据包的可变头可以看作是其附加信息,而负载则用于实现数据包的核心功能。例如,在 PUBLISH 数据包中,负载用于承载实际的应用消息,这是 PUBLISH 数据包的主要功能。PUBLISH 数据包的可变头中的 QoS、Retain 等字段提供了与应用消息相关的附加功能。SUBSCRIBE 数据包遵循类似的模式。负载部分包含要订阅的主题及其对应的订阅选项,这是 SUBSCRIBE 数据包的主要任务。TweetShareShareEmail 数据分析 MQTT 网络与协议 --> 数据分析 MQTT 网络与协议
查看全文
作者最近更新
-
Edge and IoT Predictions For 2024iotforall2023-12-22
评论0条评论