MQTT 协议学习:005-发布消息 与 对应报文 (PUBLISH、PUBACK、PUBREC、PUBREL)
背景
当有订阅者订阅了有关的主题以后,通过发布消息的消息的动作,可以让订阅者收到对应主题的消息。
根据不同的QoS 等级,通信的动作也略有不同。
PUBLISH – 发布消息 报文
PUBLISH控制报文是指从客户端向服务端或者服务端向客户端传输一个应用消息。
- 客户端使用PUBLISH报文发送应用消息给服务端,目的是分发到其它订阅匹配的客户端。
- 服务端使用PUBLISH报文发送应用消息给每一个订阅匹配的客户端。
客户端使用带通配符的主题过滤器请求订阅时,客户端的订阅可能会重复,因此发布的消息可能会匹配多个过滤器。对于这种情况,服务端必须将消息分发给所有订阅匹配的QoS等级最高的客户端。服务端之后可以按照订阅的QoS等级,分发消息的副本给每一个匹配的订阅者。
收到一个PUBLISH报文时,接收者的动作取决于QoS等级。
如果服务端实现不授权某个客户端发布PUBLISH报文,它没有办法通知那个客户端。它必须按照正常的QoS规则发送一个正面的确认,或者关闭网络连接。
PUBLISH 固定头
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
byte 1 | MQTT控制报文类型 (0x3) | DUP | QoS | RETAIN | ||||
0 | 0 | 1 | 1 | X | X | X | X | |
byte 2... | 剩余长度 |
下面我们直接看各个报文类型标志位
重发标志 DUP
保证消息可靠传输,默认为0,只占用一个字节,表示第一次发送。不能用于检测消息重复发送等。
只适用于客户端或服务器端尝试重发PUBLISH, PUBREL, SUBSCRIBE 或 UNSUBSCRIBE消息,注意需要满足以下条件:
1)当QoS > 0
2)消息需要回复确认
位置:byte1[3]
如果DUP标志被设置为0:表示这是客户端或服务端第一次请求发送这个PUBLISH报文。对于QoS 0的消息,DUP标志必须设置为0。
如果DUP标志被设置为1:表示这可能是一个早前报文请求的重发。
客户端或服务端请求重发一个PUBLISH报文时,必须将DUP标志设置为1。
服务端发送PUBLISH报文给订阅者时,收到(入站)的PUBLISH报文的DUP标志的值不会被传播。发送(出站)的PUBLISH报文与收到(入站)的PUBLISH报文中的DUP标志是独立设置的,它的值必须单独的根据发送(出站)的PUBLISH报文是否是一个重发来确定。
非规范评注
接收者收到一个DUP标志为1的控制报文时,不能假设它看到了一个这个报文之前的一个副本。
需要特别指出的是,DUP标志关注的是控制报文本身,与它包含的应用消息无关。当使用QoS 1时,客户端可能会收到一个DUP标志为0的PUBLISH报文,这个报文包含一个它之前收到过的应用消息的副本,但是用的是不同的报文标识符。
服务质量等级 QoS
这个字段表示应用消息分发的服务质量等级保证。
关于 QoS 等级 与 流程可以参考 :《Qos等级 与 会话》
位置:byte1[2:1] 。
QoS值 | Bit 2 | Bit 1 | 描述 |
---|---|---|---|
0 | 0 | 0 | 最多分发一次 |
1 | 0 | 1 | 至少分发一次 |
2 | 1 | 0 | 只分发一次 |
- | 1 | 1 | 保留位 |
PUBLISH报文不能将QoS所有的位设置为1。如果服务端或客户端收到QoS所有位都为1的PUBLISH报文,它必须关闭网络连接。
当QoS设置为1时,客户端或服务器发布消息时,需要得到对方的确认(PUBACK),如果一段时间后没收到PUBACK,那么会再次发送当前消息,并将DUP字段标记为1。
保留标志 RETAIN
用来设定一条消息是否为保留消息;如果是,那么 服务端必须存储这个应用消息和它的服务质量等级(QoS),以便它可以被分发给未来的主题名匹配的订阅者。一个新的订阅建立时,对每个匹配的主题名,如果存在最近保留的消息,它必须被发送给这个订阅者。
参考:《Retained(保留消息) 和LWT(最后遗嘱)》
位置:byte1[0] 。
如果服务端收到一条保留(RETAIN)标志为1的QoS 0消息,它必须丢弃之前为那个主题保留的任何消息。它应该将这个新的QoS 0消息当作那个主题的新保留消息,但是任何时候都可以选择丢弃它 — 如果这种情况发生了,那个主题将没有保留消息。有关存储状态的更多信息见 4.1节。
服务端发送PUBLISH报文给客户端时,如果消息是作为客户端一个新订阅的结果发送,它必须将报文的保留标志设为1 [MQTT-3.3.1-8]。当一个PUBLISH报文发送给客户端是因为匹配一个已建立的订阅时,服务端必须将保留标志设为0,不管它收到的这个消息中保留标志的值是多少。
保留标志为1且有效载荷为零字节的PUBLISH报文会被服务端当作正常消息处理,它会被发送给订阅主题匹配的客户端。此外,同一个主题下任何现存的保留消息必须被移除,因此这个主题之后的任何订阅者都不会收到一个保留消息。当作正常 意思是现存的客户端收到的消息中保留标志未被设置。服务端不能存储零字节的保留消息。
如果客户端发给服务端的PUBLISH报文的保留标识为0,服务端不能存储这个消息也不能移除或替换任何现存的保留消息。
通俗来讲:之前发的消息A是带有保留标识位(值1)的,如果此后又发了消息B(没有带保留标志位的),那么保留消息还是A(而不是B)。
对于发布者不定期发送状态消息这个场景,保留消息 常用在 新的订阅者希望会收到某主题最近的状态。
PUBLISH 的 可变头
可变报头按顺序包含主题名(Topic Name)
和报文标识符(Packet Identifier)
。
主题名 Topic Name
主题名(Topic Name)用于识别有效载荷数据应该被发布到哪一个信息通道。
主题名必须是PUBLISH报文可变报头的第一个字段。
二进制位 | 7-0 |
---|---|
byte 1 | 字符串长度的最高有效字节(MSB) |
byte 2 | 字符串长度的最低有效字节(LSB) |
byte 3 … | 如果长度大于0,这里是UTF-8编码的字符数据。 |
PUBLISH报文中的主题名不能包含通配符。
服务端发送给订阅客户端的PUBLISH报文的主题名必须匹配该订阅的主题过滤器。
报文标识符 Packet Identifier
只有当QoS等级是1或2时,报文标识符(Packet Identifier)字段才能出现在PUBLISH报文中。
报文标识符用来区分报文,特别是在重发的报文中用来标识是否是同一个报文,并在需要应答的场景中用于确定是对哪个发送报文的应答。可变报头的报文标识符(Packet Identifier)字段存在于在多个类型的报文里(占用2个字节)。这些报文是:
PUBLISH(QoS > 0时)
, PUBACK
,PUBREC
,PUBREL
,PUBCOMP
,SUBSCRIBE,
SUBACK
,UNSUBSCRIBE
,UNSUBACK
。
Bit | 7 - 0 |
---|---|
byte 1 | 报文标识符 MSB |
byte 2 | 报文标识符 LSB |
Packet ID默认是从1(0x01)开始并自增,最大为255(0xff)。
SUBSCRIBE
,UNSUBSCRIBE
和PUBLISH(QoS大于0)
控制报文必须包含一个非零的16位报文标识符(Packet Identifier)。
- 客户端每次发送一个新的这些类型的报文时都必须分配一个当前未使用的报文标识符。
- 如果一个客户端要重发这个特殊的控制报文,在随后重发那个报文时,它必须使用相同的标识符。
当客户端处理完这个报文对应的确认(ACK, CMP)后,这个报文标识符就释放可重用。
例如:QoS 1的PUBLISH对应的是
PUBACK
,QoS 2的PUBLISH对应的是PUBCOMP
,与SUBSCRIBE或UNSUBSCRIBE对应的分别是SUBACK
或UNSUBACK
。
发送一个QoS 0的PUBLISH报文时,相同的条件也适用于服务端。
QoS等于0的PUBLISH报文不能包含报文标识符。
PUBACK
, PUBREC
, PUBREL
报文必须包含与最初发送的PUBLISH报文相同的报文标识符。类似地,SUBACK
和UNSUBACK
必须包含在对应的SUBSCRIBE和UNSUBSCRIBE报文中使用的报文标识符。
PUBLISH 的 有效载荷
有效载荷包含将被发布的应用消息
,即:数据的内容和格式是应用特定的。
包含零长度有效载荷的PUBLISH报文是合法的。
有效载荷的长度这样计算:用固定报头中的剩余长度字段的值减去可变报头的长度。
实际上,应该说是
固定报头中的剩余长度字段的值 = 可变报头的长度 + 有效荷载
因为只有确定了可变头与有效荷载的长度,才可以计算固定报头中的剩余长度的值。
PUBLISH报文的 响应
PUBLISH 报文的接收者必须按照根据PUBLISH报文中的QoS等级发送响应,见下面表格的描述。
表格 3.4 – PUBLISH报文的预期响应
服务质量等级 | 预期响应 |
---|---|
QoS 0 | 无响应 |
QoS 1 | PUBACK报文 |
QoS 2 | PUBREC报文 |
PUBLISH 响应
不同的Qos 等级会导致不同的通信流程。
关于 QoS 等级 与 流程可以参考 :《Qos等级 与 会话》
PUBLISH报文 中的 Packet Identifier 是什么,下面 的 Packet Identifier便是什么。
PUBACK - 发布确认报文 (QoS 1)
PUBACK 报文 比较简单,它是对QoS 1等级的PUBLISH报文的响应。
PUBACK 报文的 组成 (没有 有效载荷) = 一个固定头(0x40 0x02) + Packet Identifier (from PUBLISH's Packet Identifier)。
PUBREC – 发布收到报文 (QoS 2,第一步)
PUBREC报文是对QoS等级2的PUBLISH报文的响应。
PUBREC 报文的 组成 (没有 有效载荷) = 一个固定头(0x50 0x02) + Packet Identifier (from PUBLISH's Packet Identifier)。
PUBREL – 发布释放(QoS 2,第二步)
PUBREL报文是对PUBREC报文的响应。
PUBREL 报文的 组成 (没有 有效载荷) = 一个固定头(0x52 0x02) + Packet Identifier (from PUBLISH's Packet Identifier)。
PUBREL控制报文固定报头的第3,2,1,0位是保留位,必须被设置为0,0,1,0。
PUBCOMP – 发布完成(QoS 2,第三步)
PUBCOMP报文是对PUBREL报文的响应。
PUBCOMP 报文的 组成 (没有 有效载荷) = 一个固定头(0x70 0x02) + Packet Identifier (from PUBLISH's Packet Identifier)。
MQTT 协议学习:005-发布消息 与 对应报文 (PUBLISH、PUBACK、PUBREC、PUBREL)的更多相关文章
- MQTT 协议学习:002- 通信报文的构成
背景 之前工作中参与有关协议调试的时候,发现对于协议帧的解析是比较重要的. 参考:<MQTT协议 -- 消息报文格式>.<基于STM32实现MQTT>.<MQTT协议从服 ...
- MQTT 协议学习:004-MQTT建立通信与 CONNECT 、CONNACK 报文
背景 上一讲 MQTT 协议学习:通信报文的构成介绍了在MQTT通信中,各报文的通信流程:从本讲开始,我们开始介绍实际中使用的报文,以及它们的组成. CONNECT - 连接请求 报文 客户端到服务端 ...
- MQTT 协议学习: 总结 与 各种定义的速查表
背景 经过几天的学习与实操,对于MQTT(主要针对 v3.1.1版本)的学习告一段落,为了方便日后的查阅 本文链接:<MQTT 协议学习: 总结 与 各种定义的速查表> 章节整理 MQTT ...
- MQTT 协议学习:000-有关概念入门
背景 从本章开始,在没有特殊说明的情况下,文章中的MQTT版本均为 3.1.1. MQTT 协议是物联网中常见的协议之一,"轻量级物联网消息推送协议",MQTT同HTTP属于第七层 ...
- MQTT协议学习总结
一.MQTT介绍 MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的“轻量级”通 ...
- MQTT 协议学习:006-订阅主题 与 对应报文(SUBSCRIBE、SUBACK、UNSUBSCRIBE、UNSUBACK)
背景 之前我们提到了怎么发布消息对应的报文:现在我们来看,订阅一个主题的报文是怎么样的. SUBSCRIBE - 订阅主题 客户端向服务端发送SUBSCRIBE报文用于创建一个或多个订阅.每个订阅注册 ...
- MQTT 协议学习:007-Keep Alive 连接保活 与 对应报文(PINGREQ、PINGRESP)
背景 keep alive 是 CONNECT 报文中可变头的一部分. 我们提到过 Broker 需要知道 Client 是否非正常地断开了和它的连接,以发送遗愿消息.实际上 Client 也需要能够 ...
- MQTT 协议学习: QoS等级 与 会话
背景 QoS 等级 与 通信的流程有关,直接影响了整个通信.而且篇幅比较长,所以我觉得应该单独拎出来讲一下. 概念 QoS 代表了 服务质量等级. 设置上,由2 位 的二进制控制,且值不允许为 3(0 ...
- MQTT 协议学习:003-MQTT通信流程介绍
背景 有关博文:通信报文的构成 . 上一讲说到可变头与消息体要结合不同的报文类型才能够进行分析(实际上,官方的文档的介绍顺序就是这样的) 那么,我们就来具体看看有关的报文类型. 在此之前 我们捋一捋完 ...
随机推荐
- Django问题 Did you rename .....a ForeignKey
给新加入的字段添加一个default默认值即可,让字段非空.然后在进行makemigrations,完成操作后删除相关默认值即可.
- flex布局(非常重要)
首先明确一点是, flex 是 flex-grow.flex-shrink.flex-basis的缩写.故其取值可以考虑以下情况: flex 的默认值是以上三个属性值的组合.假设以上三个属性同样取默认 ...
- Linux centosVMware iptables规则备份和恢复、firewalld的9个zone、firewalld关于zone的操作、firewalld关于service的操作
一.iptables规则备份和恢复 保存和备份iptables规则 service iptables save //会把规则保存到 /etc/sysconfig/iptables 把iptables规 ...
- Android Studio的HAXM不支持虚拟机
因为我的计算机是服务器,不支持虚拟机,所以报这个错了. 解决方式是直接连接物理手机,打开USB调试,安装驱动,运行项目即可.
- 解决vue更新默认值时出现的闪屏问题
在Vue项目中,对于一个展示用户个人信息的页面.有以下需求,需要判断用户个人信息是否填充过,如果填充过,需要在页面中展示已填充项(未填充项不展示):如果未填充过,需要在页面中显示另外一种元素(提示用“ ...
- 题解:luogu P3909
这个题拖了快三个月了,只因缺个快速乘(气愤.jpg). 题目链接:P3909 异或之积 你确定没人用前缀和,后缀和吗? 蒟蒻想法与众不同! 我们实验\(A[]={1,2,3,4}\). 这里计不乘6时 ...
- 搭建solr集群的时候出现 ./zkcli.sh:行13: unzip: 未找到命令
主要的原因是: linux系统下面没有安装压缩解压工具 zip 和 unzip:需要我们自己手动的安装: 利用yum命令安装即可: yum install -y unzip zip
- 同源策略、跨域、json和jsonp
同源策略 源(origin)就是协议.域名和端口号.若地址里面的协议.域名和端口号均相同则属于同源. 以下是相对于 http://www.a.com/test/index.html 的同源检测 • h ...
- 通过开源项目免费申请 IntelliJ IDEA license(激活码)
通过github开源项目免费申请 IntelliJ IDEA license(激活码) 我用来申请的github开源项目:https://github.com/Linliquan/springboot ...
- 「CF5E」Bindian Signalizing
传送门 Luogu 解题思路 很显然的一点,任何一条可能成为路径的圆弧都不可能经过最高的点,除非这条路径全是最高点. 所以我们先把最大值抠掉,把剩下的按原来的顺序排好. 从前往后.从后往前扫两次,用单 ...