物联网之MQTT3.1.1和MQTT5协议 (1) 术语部分

前言

本次博文即后续一系列博文,将就MQTT协议3.1.1和MQTT协议5.0进行介绍和描述,主要是依据官方文档进行翻译和再次编辑,将同步区别部分进行细化。另外还会推荐一些mqtt的实现,由于mqtt 5今年新出,mqtt 3版本的broker已经有许多优秀的开源项目,mqtt5完全实现的broker较少。

MQTT是物联网的协议,英文全称为Message Queuing Telemetry Transport被翻译为,消息队列遥测传输。目前为止,如今最常用的是MQTT3.1.1协议,因为是在2014年10月29日发布了最终稿,MQTT5.0的草案从2017年至今年上半年3月7号才最终确定,只是5.0的第一个版本。MQTT的初始第一版由IBM在1999年发布。

简述

MQTT是一个客户端服务端架构的发布/订阅模式的消息传输协议,构建于TCP/IP或者其他有序、可靠、双向连接的网络连接上。

它的特点有

  • 使用发布/订阅消息模式,提供了一对多的消息分发和应用之间的解耦。

  • 消息传输不需要知道负载内容

  • 提供三种等级的服务质量(QoS)

    1. QoS0: “最多一次(At most once)”,尽操作环境所能提供的最大努力分发消息。消息可能会丢失。例如,这个等级可用于环境传感器数据,单次的数据丢失没关系,因为不久之后会再次发送。
    2. QoS1: “至少一次”,保证消息可以到达,但是可能会重复。
    3. QoS2: “仅一次”,保证消息只到达一次。例如,这个等级可用在一个计费系统中,这里如果消息重复或丢失会导致不正确的收费。
  • 很小的传输消耗和协议数据交换,最大限度减少网络流量

  • 异常连接断开发生时,能通知到相关各方

    扫描二维码关注公众号,回复: 10746512 查看本文章

MQTT综述

相关术语

网络连接(Network Connection)

MQTT使用的底层传输协议基础设施。

  • 客户端使用它连接服务端
  • 提供有序的、可靠的、双向字节流传输

应用消息(Application Message)

MQTT协议通过网络传输应用数据。

MTQQ3.1.1

MQTT传输传输的应用消息通过,包含关联的服务质量(QoS)和主题(Topic)名。

MQTT5.0

当MQTT传输应用程序消息,包含有效负载数据(payload data),服务质量(QoS),属性的集合(Properties)和主题名(Topic)。

客户端(Client)

使用MQTT的程序或设备。客户端总是通过网络连接到服务端。它可以

  • 发布应用消息给其它相关的客户端
  • 订阅以请求接受相关的应用消息
  • 取消订阅以移除接受应用消息的请求
  • 与服务端断开连接

服务端(Server)

一个程序或设备,作为发送应用消息的客户端和请求订阅的客户端之间的中介。服务端

  • 接受来自客户端的网络连接
  • 接受客户端发布的应用消息
  • 处理客户端的订阅和取消订阅请求
  • 转发应用消息给符合条件的客户端订阅

订阅(Subscription)

订阅包含一个主题过滤器(Topic Filter)和一个最大的服务质量(QoS)等级。订阅与单个会话(Session)关联。会话可以包含多于一个的订阅。会话的每个订阅都有一个不同的主题过滤器。

主题过滤器(Topic Filter)

订阅中包含的一个表达式,用于表示相关的一个或多个主题。主题过滤器可以包含通配符。

会话(Session)

客户端和服务端之间的状态交互。一些会话持续时长与网络连接一样,另一些可以在客户端和服务端的多个连续网络连接间扩展。

MQTT控制报文(MQTT Control Packet)

通过网络连接发送的信息数据包。MQTT规范定义了十四种不同类型的控制报文,其中一个(PUBLISH报文)用于传输应用消息。

MQTT5.0增加至15种,其中增加了AUTH。即Authentication exchange


共享订阅(Shared Subscription,MQTT 5)

一个共享订阅包含一个主题过滤器(Topic Filter)和一个最大的服务质量(QoS)等级。一个共享订阅可以与多个订阅会话相关联,便于支持大范围消息交换模式。与共享订阅匹配的应用消息仅发送到与这些会话之一相关联的客户端。一个会话可以包括多个共享订阅,可以同时包含共享订阅与非共享订阅。

针对共享订阅的个人理解(qiwei.tan)

由于是个人理解,所以有误部分,欢迎指出

共享订阅针对场景应是数据的生产者远超出数据消费者数量,而且同一条数据(消息)只需要被任意其中一个消费者处理一次。主要是实现消费者数量处理消息的均衡负载。

比如有一个发布者发布四条消息,只需要处理一次,此时有四个订阅者共享这四条消息,实现MQTT的broker端只需要把消息分别发送到四个订阅者便可以实现消息的处理。

在这里插入图片描述


通配符订阅(Wildcard Subscription)

通配符订阅是具有包含一个或多个通配符的主题过滤器的订阅。 这允许订阅匹配多个主题名称。

主题名(Topic Name)

附加到应用程序消息的标签,该标签与服务器已知的订阅相匹配。

无效报文(Malformed Packet)

根据规范不能被正确解析的控制报文。

协议错误(Protocol Error)

解析数据包后发现错误,发现该错误包含协议不允许的数据或与客户端或服务器的状态不一致的数据。

遗嘱消息(Will Message)

在网络连接正常关闭的情况下,服务器在网络连接关闭后发布的应用程序消息。

不允许的Unicode代码点(Disallowed Unicode code point)

不应包含在UTF-8编码字符串中的Unicode控制代码和Unicode非字符集。

代码点(code point)是指与一个编码表中的某个字符对应的代码值。

数据表示

单字节数据

字节中的位从0到7。第7位是最高有效位,第0位是最低有效位。

双字节整数

双字节整数数值是使用大端序(big-endian高位字节在低位字节前面)的16位无符号整数。这意味着一个16位的字在网络上表示为最高有效位(MSB),后面跟着最低有效位(LSB)。

当物理单位长度大于1个字节时,需要区分字节顺序。关于大小端序,可以点击查看这篇博客

四字节整数(MQTT5.0新增)

四字节整数数据值是按大端序(big-endian高位字节在低位字节前面)的32位无符号整数:高位字节先于连续的低位字节。 这意味着一个32位字在网络上显示为最高有效字节(MSB),然后是下一个最高有效字节(MSB),然后是下一个最高有效字节(MSB),然后是最低有效字节(LSB)。

UTF-8编码字符串

后续描述的MQTT控制报文中的文本字段编码为 UTF-8 格式的字符串。UTF-8 是Unicode字符的有效编码,优化ASCII字符的编码以支持基于文本的通信。

除非另有说明,否则所有UTF-8编码的字符串长度都可以在0到65535字节之间。

在这里插入图片描述

图例 UTF-8编码字符串的结构

==UTF-8编码字符串中的字符数据必须是按照Unicode规范定义的有效的UTF-8格式,并在RFC3629中进行重述。特别需要指出的是,这些数据不能包含字符码在U+D800U+DFFF之间的数据。==如果服务端或客户端收到了一个包含无效UTF-8字符的控制报文,则它是无效报文。

==UTF-8编码的字符串不能包含空字符U+0000。==如果客户端或服务端收到了一个包含U+0000的控制报文,则它是无效报文。

数据不应包含下面列出的Unicode代码点的编码。 如果接收者(服务器或客户端)接收到包含其中任何一个的MQTT控制报文,则可以将其视为无效报文。 这些是禁止的Unicode代码点。

  • U+0001..U+001F控制字符
  • U+007F..U+009F 控制字符
  • Unicode规范定义的非字符代码点(例如U+0FFFF)

UTF-8编码的序列0xEF 0xBB 0xBF始终被解释为U + FEFF(零宽度非换行空白字符),无论它出现在字符串中的什么位置,都不得被数据报文接收者跳过或剥离。

非规范的例子

例如,字符串 A? 它是拉丁文大写字母A,后跟代码点U + 2A6D4(代表中日韩统一表意文字扩展B中的字符),其编码如下:

在这里插入图片描述

图例 UTF-8编码字符串非规范示例

可变字节整数

剩余长度字段使用一个变长字节编码方案,对小于 128 的值它使用单字节编码。更大的值按下面的方式处理。低 7 位有效位用于编码数据,最高有效位用于指示是否有更多的字节。因此每个字节可以编码 128 个数值和一个延续位(continuation bit)。剩余长度字段最大 4 个字节,编码值必须使用表示该值所需的最小字节数,如下表所示。

可变字节整数的大小

字节数 最小值 最大值
1 0 (0x00) 127 (0x7F)
2 128 (0x80, 0x01) 16,383 (0xFF, 0x7F)
3 16,384 (0x80, 0x80, 0x01) 2,097,151 (0xFF, 0xFF, 0x7F)
4 2,097,152 (0x80, 0x80, 0x80, 0x01) 268,435,455 (0xFF, 0xFF, 0xFF, 0x7F)

编码方案算法

用于将非负整数X编码为可变字节整数编码方案的算法如下:

do
   encodedByte = X MOD 128
   X = X DIV 128
   // if there are more data to encode, set the top bit of this byte
   // 如果还有更多数据要编码,请设置此字节的高位
   if (X > 0)
      encodedByte = encodedByte OR 128
   endif
   'output' encodedByte
while (X > 0)

MOD是模运算,DIV是整数除法,OR是位操作或(C语言中分别是%,/,|)

解码算法

可变字节整数类型的解码算法如下:

multiplier = 1
value = 0
do
   encodedByte = 'next byte from stream'
   value += (encodedByte AND 127) * multiplier
   if (multiplier > 128*128*128)
      throw Error(Malformed Variable Byte Integer)
   multiplier *= 128
while ((encodedByte AND 128) != 0)

AND 是位操作与(C 语言中的&)

这个算法终止时,value 包含的就是剩余长度的值。

二进制数据

二进制数据由一个双字节整数指示其数据长度,因此,二进制数据的长度被限制为0到65,535字节。

UTF-8字符串键值对(MQTT5.0)

UTF-8字符串对由两个UTF-8编码的字符串组成,用来表示名字-值对,第一个字符串表示名字,第二个字符串表示值。

所有的字符串必须遵循UTF-8字符串编码规范,如果接受者(客户端或者服务端)接受到一个字符串对,然而其编码并不遵循规范,则此报文为无效报文。

安全(MQTT5.0)

MQTT客户端和服务器实现应提供身份验证,授权和安全通信选项,后续会有说明。强烈建议与关键基础结构,个人身份信息或其他个人或敏感信息有关的应用程序使用这些安全性功能。

报文结构

MQTT协议通过以定义的方式交换一系列MQTT控制报文来进行操作。

MQTT控制报文最多由三部分组成,始终按照以下顺序显示,如下所示。

在这里插入图片描述

图例–MQTT控制报文的结构

固定报头

每个MQTT控制包都包含一个固定报头,如下所示。

在这里插入图片描述

图例-固定报头的格式

控制报文的类型

位置:第一个字节,二进制位 7- 4。

表示为4位无符号值的值在下表中列出。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

标志位

固定标头中第一个字节的剩余4位即[3-0]位,包含特定于每种MQTT控制数据包类型的标志,如下表所示。 如果标志位标记为“保留”,则保留该标志位以备将来使用,并且必须将其设置为列出的值。 如果收到非法的标志,则它是无效报文。

表格-标志位 Flag Bits

在这里插入图片描述

  • D U P 1 DUP^1 = 控制报文的重复分发标志
  • Q o S 2 QoS^2 = PUBLISH报文的服务质量等级
  • R E T A I N 3 RETAIN^3 = PUBLISH报文的保留标志

剩余长度

位置:从第2个字节开始。

剩余长度是一个可变字节整数,表示当前控制报文中剩余的字节数,包括可变报头和有效载荷中的数据。 剩余长度不包括用于编码剩余长度的字节数。 数据报文大小是MQTT控制数据报文中的字节总数,它等于固定报头的长度加上剩余长度。

非规范评注

例如,十进制数64会被编码为一个字节,数值是64,十六进制表示为0x40。十进制数字321(=65+2*128)被编码为两个字节,最低有效位在前。第一个字节是 65+128=193。注意最高位为1表示后面至少还有一个字节。第二个字节是2。

非规范评注

这允许应用发送最大256MB(268,435,455)大小的控制报文。这个数值在报文中的表示是:0xFF,0xFF,0xFF,0x7F。

可变报头

某些MQTT控制报文包含一个可变报头部分。它在固定报头和有效载荷之间。可变报头的内容根据报文类型的不同而不同。可变报头的报文标识符(Packet Identifier)字段存在于在多个类型的报文里。

报文标识符

许多MQTT控制数据报文类型的可变报头组件都包含一个2字节整数数据包标识符字段。 这些MQTT控制数据报文是PUBLISH(当QoS> 0),PUBACK,PUBREC,PUBREL,PUBCOMP,SUBSCRIBE,SUBACK,UNSUBSCRIBE和UNSUBACK。

图例-报文标识符字节 Packet Identifier bytes

在这里插入图片描述

需要数据报文标识符的MQTT控制数据报文如下所示:

MQTT 控制报文 报文标识符字段
CONNECT 不需要
CONNACK 不需要
PUBLISH 需要(如果 QoS > 0)
PUBACK 需要
PUBREC 需要
PUBREL 需要
PUBCOMP 需要
SUBSCRIBE 需要
SUBACK 需要
UNSUBSCRIBE 需要
UNSUBACK 需要
PINGREQ 不需要
PINGRESP 不需要
DISCONNECT 不需要
AUTH 不需要

AUTH是MQTT5.0版本的

  • QoS设置为0的PUBLISH报文不能包含报文标识符
  • 客户端每次发送一个新的SUBSCRIBE,UNSUBSCRIBE或者PUBLISH(当QoS>0时)MQTT控制报文时都必须分配一个当前未使用的非零报文标识符【16位】
  • 服务端每次发送一个新的PUBLISH(当QoS>0)MQTT控制报文时都必须分配一个当前未使用的非零报文标识符
  • 当客户端处理完这个报文对应的确认后,这个报文标识符就释放可重用。QoS 1的PUBLISH对应的是PUBACK,与SUBSCRIBE或UNSUBSCRIBE对应的分别是SUBACK或UNSUBACK。针对MQTT5.0版本来说,QoS 2的PUBLISH对应的是包含原因码128以上的PUBCOMP或PUBREC,而MQTT3.1.1来说,QoS 2的PUBLISH仅对应的是PUBCOMP。
  • 与PUBLISH,SUBSCRIBE和UNSUBSCRIBE数据报文一起使用的数据报文标识符构成一次会话中客户端和服务器的单个统一标识符集。报文标识符在任何时候都不能被多个命令使用。
  • PUBACK,PUBREC或PUBREL数据报文必须包含与最初发送的PUBLISH数据报文相同的数据报文标识符
  • 类似地,SUBACK和UNSUBACK必须包含在对应的SUBSCRIBE和UNSUBSCRIBE报文中使用的报文标识符

客户端和服务端彼此独立地分配报文标识符。因此,客户端服务端组合使用相同的报文标识符可以实现并发的消息交换

非规范评注

客户端发送标识符为0x1234的PUBLISH报文,它有可能会在收到那个报文的PUBACK之前,先收到服务端发送的另一个不同的但是报文标识符也为0x1234的PUBLISH报文。

在这里插入图片描述

属性(MQTT5.0)

CONNECT,CONNACK,PUBLISH,PUBACK,PUBREC,PUBREL,PUBCOMP,SUBSCRIBE,SUBACK,UNSUBSCRIBE,UNSUBACK,DISCONNECT和AUTH数据报文的可变报头中的最后一个字段是一组属性。 在CONNECT数据包中,有效载荷的遗愿Properties字段中还有一组可选的Properties。

属性字段由属性长度和所有属性组成。

属性长度

属性长度被编码为可变字节整数。属性长度不包括用于编码自身的字节,但包括属性的长度。如果没有属性,则必须通过包含零的属性长度来指示

属性

一个属性由一个标识符定义,该标识符定义其用途和数据类型,后跟一个值。 标识符被编码为可变字节整数。 包含对它的数据报文类型无效的标识符或包含的值不是指定数据类型的控制数据报文是无效数据报文。 如果收到,服务端或客户端使用包含原因码0x81(无效报文)CONNACK或DISCONNECT报文进行错误处理。 具有不同标识符的属性的顺序没有意义。

MQTT5属性表

在这里插入图片描述

无法确定的翻译,怕译不准确,以括号原始英文给出,例如Server Reference

非规范评注

尽管属性标识符被定义为可变字节整数,但在MTQQ5.0的规范中,所有属性标识符的长度均为一个字节。

有效载荷

一些MQTT控制数据报文包含有效载荷作为数据报文的最后部分。 在PUBLISH 报文中,是指应用消息。

在这里插入图片描述

黄色部分突出显示的是MQTT5和MQTT3.1.1的不同


MQTT5新增


原因码(MQTT5.0)

原因码是一个无符号的单字节值,指示操作的结果。 原因代码小于0x80表示操作成功完成。 成功的常规原因码为0。原因码值为0x80或更大表示失败。

CONNACK,PUBACK,PUBREC,PUBREL,PUBCOMP,DISCONNECT和AUTH控制数据报文具有单个原因码作为变量头的一部分。 SUBACK和UNSUBACK数据包在有效负载中包含一个或多个原因代码的列表。

原因码共享一组通用值,如下所示。

原因码表

在这里插入图片描述

非规范评注

对于原因码0x91(正在使用的数据报文标识符),对此的响应是尝试修复状态,或者通过使用设置为1的“Clean Start”标志位进行连接来重置会话状态,或者确定客户端或服务器实现是否有缺陷。

总结

MQTT5增加了共享订阅,属性等内容,实现负载均衡。下一篇博文将会介绍MQTT控制报文的第一个报文,CONNECT报文。

发布了189 篇原创文章 · 获赞 675 · 访问量 31万+

猜你喜欢

转载自blog.csdn.net/YuYunTan/article/details/102494675