物联网之MQTT3.1.1和MQTT5协议 (9) SUBSCRIBE报文

前言

客户端向服务端发送SUBSCRIBE报文用于创建一个或多个订阅。每个订阅(Subscription)注册客户端所感兴趣的一个或多个主题。服务器将PUBLISH数据报文发送到客户端,以转发那些被发布到与这些订阅匹配的主题的应用程序消息。SUBSCRIBE报文同样(为每个订阅)指定了服务端可以向其发送的应用消息最大QoS等级。

SUBSCRIBE - 订阅请求

固定报头

在这里插入图片描述

SUBSCRIBE报文固定报头第3,2,1,0比特位是保留位,必须被设置为0,0,1,0。服务端必须将其他的任何值都当做是不合法的并关闭网络连接。

剩余长度字段
表示可变报头的长度加上有效载荷的长度,被编码为变长字节整数。

MQTT3.1.1中可变报头的长度等于2字节

可变报头

SUBSCRIBE报文可变报头按顺序包含以下字段:报文标识符(Packet Identifier),属性(Properties)。

MQTT3.1.1则没有属性

下图展示MQTT3.1.1和MQTT5的一个包含报文标识符为10,且没有属性的SUBSCRIBE可变报头。

MQTT3.1.1本身就没有属性,而且没有字节表示

在这里插入图片描述

SUBSCRIBE属性

属性长度

SUBSCRIBE报文可变报头中的属性长度被编码为变长字节整数。

订阅标识符

11 (0x0B)Byte,订阅标识符(Subscription Identifier)标识符。

跟随其后的是一个变长字节整数表示订阅标识符。订阅标识符取值范围从1到268,435,455。订阅标识符的值为0或包含多个订阅标识符将造成协议错误(Protocol Error)。

订阅标识符与SUBSCRIBE报文所创建或修改的订阅(Subscription)相关联。如果包含订阅标识符,它将与订阅一起被存储。如果未指定此属性,则订阅被存储时将不包含订阅标识符。

用户属性

38 (0x26)Byte,用户属性(User Property)标识符。

跟随其后的是UTF-8字符串键值对。

用户属性允许出现多次,以表示多个名字/值对。同样的名字允许出现多次。

SUBSCRIBE报文的用户属性可以被客户端用来向服务端发送订阅相关的属性。目前MQTT5规范不定义这些属性的意义。

SUBSCRIBE载荷

【MQTT 3.1.1】

  • SUBSCRIBE报文的有效载荷包含了一个主题过滤器列表,它们表示客户端想要订阅的主题。SUBSCRIBE报文有效载荷中的主题过滤器列表必须是UTF-8字符串 。
  • 服务端应该支持包含通配符的主题过滤器。如果服务端选择不支持包含通配符的主题过滤器,必须拒绝任何包含通配符过滤器的订阅请求。每一个过滤器后面跟着一个字节,这个字节被叫做 服务质量要求(Requested QoS)。它给出了服务端向客户端发送应用消息所允许的最大QoS等级。
  • SUBSCRIBE报文的有效载荷必须包含至少一对主题过滤器/QoS字段组合。没有有效载荷的SUBSCRIBE报文是违反协议的。
  • 请求的最大服务质量等级字段编码为一个字节,它后面跟着UTF-8编码的主题名,那些主题过滤器/QoS 组合是连续地打包。

【MQTT 5】

  • SUBSCRIBE报文的载荷包含一列主题过滤器,指明客户端希望订阅的主题。主题过滤器必须为UTF-8 编码的字符串。每个主题过滤器之后跟着一个订阅选项(Subscription Options)字节。

    与MQTT3.1.1不一样的描述,MQTT3.1.1是服务质量要求(QoS),而MQTT5是订阅选项,但是本质都是针对最大服务质量的字段

  • 载荷必须包含至少一个主题过滤器/订阅选项对。不包含载荷的SUBSCRIBE报文将造成协议错误(Protocol Error)。

订阅选项

订阅选项的第0和1比特代表最大服务质量字段。

订阅选项的第0和1比特代表最大服务质量字段。此字段给出服务端可以向此客户端发送的应用消息的最大QoS等级。最大服务质量字段为3将造成协议错误(Protocol Error)。

订阅选项的第2比特表示非本地(No Local)选项。值为1,表示应用消息不能被转发给发布此消息的客户标识符。时把非本地选项设为1将造成协议错误(Protocol Error)

订阅选项的第3比特表示发布保留(Retain As Published)选项。值为1,表示向此订阅转发应用消息时保持消息被发布时设置的保留(RETAIN)标志。值为0,表示向此订阅转发应用消息时把保留标志设置为0。当订阅建立之后,发送保留消息时保留标志设置为1。

订阅选项的第4和5比特表示保留操作(Retain Handling)选项。此选项指示当订阅建立时,是否发送保留消息。此选项不影响之后的任何保留消息的发送。如果没有匹配主题过滤器的保留消息,则此选项所有值的行为都一样。值可以设置为:

  • 0 = 订阅建立时发送保留消息
  • 1 = 订阅建立时,若该订阅当前不存在则发送保留消息
  • 2 = 订阅建立时不要发送保留消息

保留操作的值设置为3将造成协议错误(Protocol Error)。

订阅选项的第6和7比特为将来所保留。服务端必须把此保留位非0的SUBSCRIBE报文当做无效报文。

非本地(No Local)和发布保留(Retain As Published)订阅选项在客户端把消息发送给其他服务端的情况下,可以被用来实现桥接。

已存在订阅的情况下不发送保留消息是很有用的,比如重连完成时客户端不确定订阅是否在之前的会话连接中被创建。

不发送保存的保留消息给新创建的订阅是很有用的,比如客户端希望接收变更通知且不需要知道最初的状态。

对于某个指示其不支持保留消息的服务端,发布保留和保留处理选项的所有有效值都将得到同样的结果:订阅时不发送任何保留消息,且所有消息的保留标志都会被设置为0。

SUBSCRIBE报文有效载荷格式

在这里插入图片描述

展示两个版本的SUBSCRIBE载荷示例,包含2个主题过滤器:第一个为“a/b” ,QoS为1;第二个为“c/d”, QoS为2。

在这里插入图片描述

二者纯数据一样,描述上不一样

SUBSCRIBE行为

  • 服务端收到客户端发送的一个SUBSCRIBE报文时,必须使用SUBACK报文响应。SUBACK报文必须和等待确认的SUBSCRIBE报文有相同的报文标识符

  • 允许服务端在发送SUBACK报文之前就开始发送与订阅相匹配的PUBLISH报文。

  • 如果服务端收到一个SUBSCRIBE报文,报文的主题过滤器与一个当前会话订阅【MQTT5中的非共享订阅】的主题过滤器相同,那么必须使用新的订阅彻底替换现存的订阅。新订阅的主题过滤器和之前订阅的相同,但是它的最大QoS值【MQTT5的订阅选项】可以不同。

  • 与这个主题过滤器匹配的任何现存的保留消息必须被重发,但是发布流程不能中断。

    MQTT5还需要在保留处理选项为0的情况下,MQTT3.1.1则直接保留处理选项为0。

  • 如果主题过滤器不同于任何当前会话任何订阅的过滤器,服务端会创建一个新的订阅并发送所有匹配的保留消息。

    MQTT5中强调主题过滤器是服务端收到的非共享主题过滤器,创建的新的订阅则是非共享订阅。而且如果保留处理选项不为2,所有相匹配的保留消息将发送给客户端。在MQTT3.1.1中保留信息则默认发送给客户端

  • 如果服务端收到包含多个主题过滤器的SUBSCRIBE报文,它必须如同收到了一系列的多个SUBSCRIBE报文一样处理那个,除了需要将它们的响应合并到一个单独的SUBACK报文发送。

  • ==【MQTT3.1.1】==服务端发送给客户端的SUBACK报文对每一对主题过滤器 和QoS等级都必须包含一个返回码。这个返回码必须表示那个订阅被授予的最大QoS等级,或者表示这个订阅失败。服务端可以授予比订阅者要求的低一些的QoS等级。为响应订阅而发出的消息的有效载荷的QoS必须是原始发布消息的QoS和服务端授予的QoS两者中的最小值。如果原始消息的QoS是1而被授予的最大QoS是0,允许服务端重复发送一个消息的副本给订阅者。

对某个特定的主题过滤器,如果正在订阅的客户端被授予的最大QoS等级是1,那么匹配这个过滤器的QoS等级0的应用消息会按QoS等级0分发给这个客户端。这意味着客户端最多收到这个消息的一个副本。从另一方面说,发布给同一主题的QoS等级2的消息会被服务端降级到QoS等级1再分发给客户端,因此客户端可能会收到重复的消息副本。

如果正在订阅的客户端被授予的最大QoS等级是0,那么原来按QoS等级2发布给客户端的应用消息在繁忙时可能会丢失,但是服务端不应该发送重复的消息副本。发布给同一主题的 QoS等级1的消息在传输给客户端时可能会丢失或重复。

使用QoS等级2订阅一个主题过滤器等于是说:我想要按照它们发布时的QoS等级接受匹配这个过滤器的消息 。这意味着,确定消息分发时可能的最大QoS等级是发布者的责任,而订阅者可以要求服务端降低QoS到更适合它的等级。

【MQTT 5】

  • 如果服务端收到的非共享主题过滤器(Non-shared Topic Filter)不同于当前会话的任何主题过滤器,一个新的非共享订阅将被创建。如果保留处理选项不为2,所有相匹配的保留消息将发送给客户端。

  • 如果服务端收到的主题过滤器与服务端已存在的某个共享订阅(Shared Subscription)主题过滤器相同,则将此会话添加到该共享订阅中。不发送任何保留消息。

  • 如果服务端收到的共享订阅主题过滤器(Shared Subscription Topic Filter)与任何已存在的共享订阅主题过滤器都不同,一个新的共享订阅将被创建。将此会话作为订阅者添加到该共享订阅。不发送任何保留消息。

  • 服务端发送给客户端的SUBACK报文必须为每一个主题过滤器/订阅选项对包含一个原因码 。 此原因码必须说明为该订阅授予的最大QoS等级,或指示订阅失败。服务端可能授予了低于订阅者所请求的最大QoS等级。响应该订阅的应用消息QoS等级必须为该消息发布时的QoS等级和服务端授予的最大QoS等级二者最小值。在原始消息发布的QoS等级为1,且授予的最大QoS等级为0的情况下,服务端允许发送重复的消息副本给订阅者。

    与MQTT3.1.1仅描述上不一样

订阅标识符(MQTT 5)

订阅标识符是服务端的会话状态的一部分,并将在收到PUBLISH报文时返回给客户端。当服务端收到客户端的UNSUBSCRIBE报文时,服务端将此会话标识符从服务端的会话状态中移除:当服务端收到客户端的UNSUBSCRIBE报文,当服务端收到客户端对同样主题过滤器的SUBSCRIBE报文但订阅标识符不同或没有订阅标识符,或者当服务端在CONNACK报文中将会话存在标志设置为0。

订阅标识符不构成客户端的会话状态的一部分。在一个有用的实现中,客户端将订阅标识符与其他客户端状态相关联,此客户端状态将被移除:当客户端取消订阅,当客户端以不同的订阅标识符或没有订阅标识符订阅同样的主题过滤器,或者当客户端收到的CONNACK报文中会话存在标志被设置为0。

服务端在重传的PUBLISH报文中无需使用同一组订阅标识符。客户端可以通过发送包含与当前会话已存在的主题过滤器的SUBSCRIBE报文进行重新订阅。如果客户端在PUBLISH报文初传之后重新订阅并使用了不同的订阅标识符,允许服务端在任何重传中使用初传所包含的订阅标识符,或者在重传中使用此新的订阅标识符。不允许服务端在发送了包含新的订阅标识符的PUBLISH报文之后再次使用旧的订阅标识符。

使用场景,用以阐述订阅标识符:

  • 客户端实现指示某条发布消息匹配多个订阅的编程接口,客户端实现每次订阅时生成新的订阅标识符。如果返回的发布消息包含多个订阅标识符,则该发布消息匹配多个订阅。
  • 客户端实现允许订阅者将消息定向到其相关联的订阅的回调,客户端实现生成映射到唯一回调的订阅标识符。收到某条发布消息时,使用订阅标识符决定触发哪一个回调。
  • 客户端实现在发布消息时返回程序用于订阅的主题字符串,为此客户端生成一个唯一标识了该主题过滤器的标识符。收到某条发布消息时,客户端实现使用此标识符查找原始主题过滤器,并将主题过滤器返回给其应用程序。
  • 网关(Gateway)将从服务端收到的发布消息转发给向该网关做了订阅的客户端,网关实现维护其收到的每个唯一的订阅过滤器到其收到的一组客户标识符–订阅标识符对的映射,网关对它转发给服务端的每个主题过滤器生成一个唯一的标识符。收到某条发布消息时,网关使用从服务端收到的订阅标识符查找对应的客户标识符–订阅标识符对,并把它们加入发送给客户端的PUBLISH报文中。如果上游服务端因为消息匹配了多个订阅而发送了多个PUBLISH报文,则此行为将反映到客户端。
发布了189 篇原创文章 · 获赞 675 · 访问量 31万+

猜你喜欢

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