MQTT通配符
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MQTT通配符相关的知识,希望对你有一定的参考价值。
参考技术A 话题名称和话题过滤器(MQTT“5.0”协议版本和MQTT“3.1.1”协议版本)4.7.1 主题通配符 Topic wildcards
主题层级(topic level)分隔符用于将结构化引入主题名。如果存在分隔符,它将主题名分割为多个 主题层级 topic level 。
订阅的主题过滤器可以包含特殊的通配符,允许客户端一次订阅多个主题。
主题过滤器中可以使用通配符,但是主题名 不能 使用通配符 [MQTT-4.7.0-1]。
4.7.1.1 主题层级分隔符 Topic level separator
斜杠(“/” U+002F)用于分割主题的每个层级,为主题名提供一个分层结构。当客户端订阅指定的主题过滤器包含两种通配符时,主题层级分隔符就很有用了。主题层级分隔符可以出现在主题过滤器或主题名字的任何位置。相邻的主题层次分隔符表示一个零长度的主题层级。
4.7.1.2 多层通配符 Multi-level wildcard
数字符号(“#” U+0023)是用于匹配主题中任意层级的通配符。多层通配符表示它的父级和任意数量的子层级。多层通配符 必须 单独指定,或者跟在主题层级分隔符后面。不管哪种情况,它都 必须 是主题过滤器的最后一个字符 [MQTT-4.7.1-1]。
非规范评注
例如,如果客户端订阅主题 “sport/tennis/player1/#”,它会收到使用下列主题名发布的消息:
“sport/tennis/player1”
“sport/tennis/player1/ranking”
“sport/tennis/player1/score/wimbledon”
非规范评注
“sport/#”也匹配单独的 “sport” 主题名,因为#包括它的父级。
“#”是有效的,会收到所有的应用消息。
“sport/tennis/#”也是有效的。
“sport/tennis#”是无效的。
“sport/tennis/#/ranking”是无效的。
4.7.1.3 单层通配符 Single-level wildcard
加号(“+” U+002B) 是只能用于单个主题层级匹配的通配符。
在主题过滤器的任意层级都可以使用单层通配符,包括第一个和最后一个层级。在使用它时,它 必须 占据过滤器的整个层级 [MQTT-4.7.1-2]。可以在主题过滤器中的多个层级中使用它,也可以和多层通配符一起使用。
非规范评注
例如,“sport/tennis/+”匹配“sport/tennis/player1”和“sport/tennis/player2”,但是不匹配“sport/tennis/player1/ranking”。同时,由于单层通配符只能匹配一个层级,“sport/+”不匹配“sport”但是却匹配 “sport/”。
“+” 是有效的。
“+/tennis/#” 是有效的。
“sport+” 是无效的。
“sport/+/player1” 也是有效的。
“/finance” 匹配 “+/+” 和 “/+” ,但是不匹配 “+”。
4.7.2 以$开头的主题 Topics beginning with $
服务端 不能 将$字符开头的主题名匹配通配符(#或+)开头的主题过滤器 [MQTT-4.7.2-1]。服务端 应该 阻止客户端使用这种主题名与其它客户端交换消息。服务端实现 可以 将$开头的主题名用作其他目的。
非规范评注
$SYS/被广泛用作包含服务器特定信息或控制接口的主题的前缀。
应用不能使用$字符开头的主题。
非规范评注
订阅“#”的客户端不会收到任何发布到以“$”开头主题的消息。
订阅“+/monitor/Clients”的客户端不会收到任何发布到“$SYS/monitor/Clients”的消息。
订阅“$SYS/#”的客户端会收到发布到以“$SYS/”开头主题的消息。
订阅“$SYS/monitor/+” 的客户端会收到发布到“$SYS/monitor/Clients”主题的消息。
如果客户端想同时接受以“$SYS/”开头主题的消息和不以$开头主题的消息,它需要同时订阅“#”和“$SYS/#”。
4.7.3 主题语义和用法 Topic semantic and usage
下列规则应用于主题名和主题过滤器:
所有的主题名和主题过滤器 必须 至少包含一个字符 [MQTT-4.7.3-1]。
主题名和主题过滤器是大小写敏感的。
主题名和主题过滤器可以包含空格字符。
主题名或主题过滤器以前置或后置斜杠“/”区分。
只包含斜杠“/”的主题名或主题过滤器是合法的。
主题名和主题过滤器 不能 包含空字符(Unicode U+0000) [ Unicode ] [MQTT-4.7.3-2]。
主题名和主题过滤器是UTF-8编码字符串,它们 不能 超过65535字节 [MQTT-4.7.3-3]。见1.5.4节。
除了不能超过UTF-8编码字符串的长度限制之外,主题名或主题过滤器的层级数量没有其它限制。
匹配订阅时,服务端 不能 对主题名或主题过滤器执行任何规范化(normalization)处理, 不能 修改或替换任何未识别的字符 [MQTT-4.7.3-4]。主题过滤器中的每个非通配符层级需要逐字符匹配主题名中对应的层级才算匹配成功。
非规范评注
使用UTF-8编码规则意味着,主题过滤器和主题名的比较可以通过比较编码后的UTF-8字节或解码后的Unicode字符。
非规范评注
“ACCOUNTS”和“Accounts”是不同的主题名。
“Accounts payable”是合法的主题名
“/finance”和“finance”是不同的。
如果订阅的主题过滤器与消息的主题名匹配,应用消息会被发送给每一个匹配的客户端订阅。主题资源 可以 是管理员在服务端预先定义好的,也 可以 是服务端收到第一个订阅或使用那个主题名的应用消息时动态添加的。服务端也 可以 使用一个安全组件有选择地授权客户端使用某个主题资源。
备注:笔者摘录于官方网站。
MQTT协议探究
1 回顾与本次目标
1.1 回顾
- 主题通配符
- 主题语义和用法
- WireShark进行抓包分析了报文
- 报文分析:
- SUBSCRIBE——订阅主题
- SUBACK——订阅确认
- UNNSUBSCRIBE——取消订阅
- UNSUBACK——取消订阅确认
- PUBLISH——发布消息(Qos0,服务质量等级下一节再说吧)
1.2 本节目标
- 服务质量等级
- PUBLISH——发布消息(Qos1 Qos2)
- PUBACK——发布确认
- PUBREC——发布收到
- PUBREL——发布释放
- PUBCOMP——发布完成
2 MQTT控制报文格式(补充)
2.1 控制报文的类型
名字 | 值 | 报文流动方向 | 描述 |
---|---|---|---|
PUBLISH | 3 | 双向 | 发布消息 |
PUBACK | 4 | 双向 | QoS 1消息发布收到确认 |
PUBREC | 5 | 双向 | QoS 2发布收到(保证交付第一步) |
PUBREL | 6 | 双向 | QoS 2发布释放(保证交付第二步) |
PUBCOMP | 7 | 双向 | QoS 2消息发布完成(保证交互第三步) |
2.2 标识符
控制报文 | 固定报文标志 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
---|---|---|---|---|---|
PUBLISH | Used in MQTT 3.1.1 | DUP | QoS | QoS | RETAIN |
PUBACK | Reserved | 0 | 0 | 0 | 0 |
PUBREC | Reserved | 0 | 0 | 0 | 0 |
PUBREL | Reserved | 0 | 0 | 1 | 0 |
PUBCOMP | Reserved | 0 | 0 | 0 | 0 |
- DUP = 控制报文的重复分发标志
- Qos = PUBLISH报文的服务质量等级
- RETAIN = PUBLISH报文是否保留标志
2.3 报文标识符
- Client每次发送一个新的报文时都必须分配一个未使用的报文标识符。
- Client如果进行重发报文必须使用相同的标识符。
- 当Client处理完这个报文对应的确认后,这个报文标识符就释放可重用。
- QoS 1的PUBLISH对应的是PUBACK
- QoS 2的PUBLISH对应的是PUBCOMP
控制报文 | 报文标识符字段 |
---|---|
PUBLISH | 需要(如果QoS > 0,Qos=0时不能带) |
PUBACK | 需要 |
PUBREC | 需要 |
PUBREL | 需要 |
PUBCOMP | 需要 |
2.4 有效载荷
控制报文 | 有效载荷 |
---|---|
PUBLISH | 可选(允许发空负载) |
PUBACK | 不需要 |
PUBREC | 不需要 |
PUBREL | 不需要 |
PUBCOMP | 不需要 |
3 服务质量等级和协议流程
3.1 概述
- 分发协议是对称的,客户端和服务端既可以是发送者也可以是接收者。
- 分发协议关注的是从单个发送者到单个接收者的应用消息。
- 服务端分发应用消息给多个客户端时,每个客户端独立处理。
- 分发给客户端的出站应用消息和入站应用消息的QoS等级可能是不同的。
3.2 QoS 0:最多分发一次
- 接收者不会发送响应(无需确认送达),发送者也不会重试(DUP=0)
- 发送者必须发送QoS=0,DUP=0的PUBLISH报文
- 协议流程:
发送者 | 方向 | 接收者 |
---|---|---|
PUBLISH报文 Qos=0 DUP=0 | ||
-------------------> | ||
分发应用消息给适当的后续接收者(们) |
3.3 QoS 1: 至少分发一次
- QoS 1的PUBLISH报文的可变报头中包含一个报文标识符,需要PUBACK报文(带上报文标识符)确认。
- 发送者:
- 新消息都必须分配一个未使用的报文标识符(收到PUBACK时,该报文标识符可以重用)。
- 发送的PUBLISH报文必须包含报文标识符且QoS=1,DUP=0(不重发)。
- 必须将这个PUBLISH报文看作是未确认的 ,直到从接收者那收到对应的PUBACK报文。
- 接收者:
- 响应的PUBACK报文必须包含一个报文标识符 ,这个标识符来自接收到的、已经接受所有权的PUBLISH报文。
- 发送了PUBACK报文之后,接收者必须将任何包含相同报文标识符的入站PUBLISH报文当作一个新的消息,并忽略它的DUP标志的值。
- 协议流程:
发送者 | 方向 | 接收者 |
---|---|---|
存储消息 | ||
PUBLISH报文 QoS=1, DUP=0 报文标识符 | -------------------> | |
开始应用消息的后续分发 | ||
<------------------- | PUBACK报文,带报文标识符 | |
丢弃消息 |
3.4 QoS 2: 仅分发一次
- 消息丢失和重复都是不可接受的
- 消息可变报头中有报文标识符
- 发送者:
- 新消息都必须分配一个未使用的报文标识符(收到PUBCOMP时,该报文标识符可以重用)。
- PUBLISH报文必须包含报文标识符且报文的QoS=2,,DUP=0。
- 必须将这个PUBLISH报文看作是未确认的 ,直到从接收者那收到对应的PUBREC报文。
- 收到PUBREC报文后必须发送一个PUBREL报文(报文标识符)。
- 必须将这个PUBREL报文看作是 未确认的 ,直到从接收者那收到对应的PUBCOMP报文。
- 一旦发送了对应的PUBREL报文就不能重发这个PUBLISH报文。
- 接收者:
- 响应的PUBREC PUBREL PUBCOMP报文必须包含相同的报文标识符
- 协议流程图:Client -> Server
发送者 | 方向 | 接收者 |
---|---|---|
存储消息 | ||
发送PUBLISH报文,Qos2,DUP=0,带报文标识符 | ||
-> | ||
方法A:存储消息 方法B:存储报文标识符,开始向前分发这个应用消息 |
||
发送PUBREC报文,带报文标识符 | ||
<- | ||
丢弃消息,存储PUBREC中的报文标识符 | ||
发送PUBREL报文,带报文标识符 | ||
-> | ||
方法A:开始向前分发应用消息并丢弃 方法B:丢弃报文标识符 |
||
发送PUBCOMP报文,带报文标识符 | ||
<- | ||
丢弃已保存的报文标识符 |
- 协议流程图:Server -> Subscriber(来自:http://www.blogjava.net/yongboy/archive/2014/02/15/409893.html)
Server | Message and direction | Subscriber |
---|---|---|
QoS = 2 DUP = 0 Message ID = x |
PUBLISH ------> |
Action: Store message |
PUBREC <------- |
Message ID = x | |
Message ID = x | PUBREL -------> |
Actions:Make message available |
PUBCOMP <----- |
Message ID = x |
4 MQTT控制报文示例
4.1 PUBLISH – 发布消息
(1)WireShark抓包获取报文
# Qos1
MQ Telemetry Transport Protocol, Publish Message
Header Flags: 0x32 (Publish Message)
0011 .... = Message Type: Publish Message (3)
.... 0... = DUP Flag: Not set
.... .01. = QoS Level: At least once delivery (Acknowledged deliver) (1)
.... ...0 = Retain: Not set
Msg Len: 18
Topic Length: 4 # 0x0004
Topic: TEST
Message Identifier: 1 # 0x0001,报文标识符
Message: HelloWorld # 18 - 2 - 4 - 2 = 10个字节
# Qos2
MQ Telemetry Transport Protocol, Publish Message
Header Flags: 0x34 (Publish Message)
0011 .... = Message Type: Publish Message (3)
.... 0... = DUP Flag: Not set
.... .10. = QoS Level: Exactly once delivery (Assured Delivery) (2)
.... ...0 = Retain: Not set
Msg Len: 18
Topic Length: 4
Topic: TEST
Message Identifier: 2
(2)固定报头
重发标志:DUP为0,代表Client第一次发这个报文;DUP为1,代表Client重发已发的报文。对于Qos为0时,DUP必须为0。
服务质量等级
Qos | Bit2 | Bit1 | 描述 |
---|---|---|---|
0 | 0 | 0 | 最大分发一次 |
1 | 0 | 1 | 至少一次 |
2 | 1 | 0 | 只分发一次 |
- | 1 | 1 | 保留位 |
(3)响应
服务质量等级 | 预期响应 |
---|---|
Qos0 | 无响应 |
Qos1 | PUBACK报文 |
Qos2 | PUBREC报文 |
4.2 PUBACK –发布确认
(1)WireShark抓包获取报文
MQ Telemetry Transport Protocol, Publish Ack
Header Flags: 0x40 (Publish Ack)
0100 .... = Message Type: Publish Ack (4)
.... 0000 = Reserved: 0
Msg Len: 2
Message Identifier: 1 # 报文标识符
(2)概述
- PUBACK报文只需要表明接收者收到了某条PUBLISH报文即可。
- Client设置CleanSession=0重连时,Client和Server必须使用原始的报文标识符重发未确认的PUBLISH报文。
- 因为存在重发和报文标志符的复用(Receiver返回PUBACK后,即使有相同的报文标识符,也认为是新的PUBLISH报文),所以可能存在转发超过一次(Qos1只保证至少1次)的情况。
4.3 PUBREC – 发布收到(QoS 2,第一步)
(1)WireShark抓包获取报文
MQ Telemetry Transport Protocol, Publish Received
Header Flags: 0x50 (Publish Received)
0101 .... = Message Type: Publish Received (5)
.... 0000 = Reserved: 0
Msg Len: 2
Message Identifier: 2
(2)概述
- 3.4节提到Reciver收到Qos2的PUBLISH报文后,可以有两种处理方式
- A:存储消息
- B:存储报文标识符(不再分发相同报文标识符的PUBLISH报文),开始分发这个应用消息
- PUBREC报文是为了告诉Sender收到了消息
- 其实PUBREC与PUBACK作用相同,表示Receiver已收到消息,所以可以把存储在Sender的消息删除(消息的所有权转让)
4.4 PUBREL – 发布释放
(1)WireShark抓包获取报文
MQ Telemetry Transport Protocol, Publish Release
Header Flags: 0x62 (Publish Release)
0110 .... = Message Type: Publish Release (6)
.... 0010 = Reserved: 2
Msg Len: 2
Message Identifier: 2
(2)概述
- Sender收到PUBREC之前,Sender仍然可能在发送相同报文标识符的PUBLISH报文,所以收到PUBREC之后需要把报文标识符记录下来(不再发送该报文标识符的PUBLISH报文)。
- Sender发送PUBREL报文是为了通知Receiver,可以开始接收相同报文标识符的PUBLISH报文了(报文标识符的复用)。
- 但Sender在没有收到响应(PUBCOMP)之前,仍然不会去发送相同报文标识符的PUBLISH报文。
4.5 PUBCOMP – 发布完成
(1)WireShark抓包获取报文
MQ Telemetry Transport Protocol, Publish Complete
Header Flags: 0x70 (Publish Complete)
0111 .... = Message Type: Publish Complete (7)
.... 0000 = Reserved: 0
Msg Len: 2
Message Identifier: 2
(2)概述
- Receiver收到了PUBREL报文
- A:开始分发消息并丢弃
- B:丢弃报文标识符(可以接收相同报文标识符的PUBLISH报文)
- 发送PUBCOMP告知Sender,可以发送相同报文标识符的PUBLISH报文了。
以上是关于MQTT通配符的主要内容,如果未能解决你的问题,请参考以下文章