物联网 MQTT 服务质量级别
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~
翻译人:Tnecesoc,该成员来自云+社区翻译社
消息队列遥测传输(MQTT)是一种客户端服务器发布 / 订阅消息传输协议。它轻量,开放,简单,其设计也易于实施。这些特性使其非常适合用于很多情况,包括在网络连接受限的,需要代码长度较小且 / 或网络带宽非常重要的环境里面,例如在机器对机器(M2M)和物联网(IoT)环境中的通信。该协议通过 TCP / IP 或其他能提供有序,无损,双向的连接的网络协议运行。
MQTT支持三种服务质量级别,如上图所示:
最多发送一次(发完就忘),也就是不确认
至少发送一次,需要进行确认
正好发送一次,要进行 4 步握手
QoS(服务质量)定义了服务端(Broker) / 客户端(Client)确保能收到消息的工作或尝试的方式。消息可以以任何 QoS 级别发送,客户端也可以选择以任意 QoS 级别来订阅主题,后者选择的是他们能收到的最高 QoS 级别。
例如,如有消息以 QoS 2 级别发布并且有一客户端以 Qos 0 级别订阅了相应主题,则那一客户端就会以 QoS 0 级别收到该消息。如果有第二个客户端也订阅了相同的主题,但用的是 QoS 2,则它将以 QoS 2 级别收到这一消息。
举另外一个例子,如有一客户端以 QoS 2 订阅了一个主题,并且有一消息以 QoS 0 在相应主题上发布,则客户端将会基于 QoS 0 级别接收这一消息。高级的 QoS 会更可靠,但也会带来更高的延迟,并占用更多的带宽。
每个 QoS 级别的一些细节就如下所示。MQTT 控制数据包内容的表格位于本文的最后部分,用于描述来自每个 QoS 流的控制数据包。
服务质量级别 0
该消息最多只发送一次,或者在通过网络的传送受阻的时候根本不发送。发送的消息不会被保存。如果客户端断开了连接,或者服务端出现了故障,该消息可能就会因此丢失。这也是最快的传输模式。MQTT 协议并没有要求服务器端将 QoS = 0 的发布消息转发给客户端。如果客户端在服务器收到发布的消息时断开了连接,则发布的消息可能会被丢弃,具体取决于服务器。遥测(MQXR)服务不会丢弃以 QoS = 0 发送的消息。它们会被作为非持久消息而保存,且只有在队列管理器停止运作时才会被丢弃。
在 QoS 0 传送协议中:
发送者:必须发送 QoS = 0,DUP = 0 的 PUBLISH 包;
接收者:在接收到 PUBLISH 包的同时也接受消息的所有权。
服务质量级别 1
该消息至少发送一次。如果发送方没有收到确认包,则会再次发送加上 DUP 标志的该消息,直到收到确认包为止。因此,接收者可能会把相同的消息发送好几次,并且也可能把它处理了好几遍。消息必须保存在发送者以及接收者的本地环境里面,直到这一消息被妥善处理为止。接收者在处理完消息后会把消息删掉。如果接收者是个服务端,则它会将把该消息发布给其订阅者作为对消息的处理。如果接收者是客户端,则会将把消息传递给作为订阅者的应用程序作为处理。在消息被删除之后,接收方会向发送方发送确认包。发送方在收到接收方的确认后会删掉保存在发送方的消息。
这个级别可以用于传送例如环境传感器这样的数据。在这种情况下,单个读数的传送失败了也没多大关系,因为传感器很快就会再把读数发送一遍。
在 QoS 1 传送协议中:
-
发送方:
必须在每次有新的应用消息发布时为其分配一个没被占用的包标识符。
必须发送一个 PUBLISH 包,其中包含 QoS = 1,DUP = 0 的包标识符。
必须将 PUBLISH 数据包视为 “未经确认” 的,直到它收到了接收方发来的,相应的 PUBACK 数据包为止。
一旦发送者收到 PUBACK 包,对应的消息的包标识符就能收回并重用。请注意,当发送方正在等待接收确认时,它可以用不同的包标识符发送更多的 PUBLISH 包。
-
接收方:
在接受了应用消息的所有权后,必须用包含传入 PUBLISH 包的包标识符的 PUBACK 包来进行响应。
在发送 PUBACK 包后,接收方必须把每一个传入的包含相同包标识符 PUBLISH 包视为一个全新的发布消息,而不管这些发布消息有没有加上 DUP 标志。
服务质量级别 2
该消息始终只发送一次。消息必须存储在发送方和接收方的本地环境中,直到它被妥善处理为止。QoS = 2 是最安全但也是最慢的传输模式。从发送方删掉消息之前,发送方和接收方之间至少需要两次相互的传输。在第一次传输后,接收方就可以开始处理这一消息。在第一次互传中,发送方会发送消息并从接收方拿到对这一消息的确认。如果发送方没有收到确认,则会再次发送加上了 DUP 标志的该消息,直至收到确认。在第二次互传中,发送方通过给接收方发送 PUBREL 消息来告知后者它可以完成对发布的消息的处理了。如果发送方没有收到接收方对 PUBREL 消息的确认,则会把 PUBREL 消息再发一遍,直到收到确认为止。当发送者收到对 PUBREL 消息的确认时,发送者就会删掉它保存的消息。接收者可以在第一或第二次互传的时候处理消息,只要它不把消息又重新处理一遍就可以了。如果接收者是服务端,它会将消息发布给订阅者。如果接收方是客户端,它会将消息传递给作为订阅者的应用程序。最后接收方会向发送方发送处理完成的消息,来表明它已完成了消息的处理。
举例来说,计费系统可以使用这个级别,因为消息的重复或丢失会导致这样的应用产生错误的计费。
在 QoS 2 传送协议中:
-
发送方:
必须在每次有新的应用消息发布时为其分配一个没被占用的包标识符。
必须发送一个包含 QoS = 2,DUP = 0 的包标识符的 PUBLISH 包。
必须将 PUBLISH 数据包视为 “未经确认” 的,直到它收到了接收方发来的,相应的 PUBREC 数据包为止。
当它从接收器收到一个 PUBREC 包时,必须发送一个 PUBREL 包。这个 PUBREL 包应该包含与原始 PUBLISH 分组相同的包标识符。
必须将 PUBREL 数据包视为 “未经确认” 的,直到它从接收方收到了相应的 PUBCOMP 包为止。
一旦发送了相应的 PUBREL 包,发送方就不能再发送原始的 PUBLISH 包。一旦发送者收到 PUBCOMP 包,包标识符就可以收回并重用。注意,当发送方正在等待接收确认时,它可以使用不同的包标识符发送更多的 PUBLISH 包。
-
接收方:
在接受了 PUBLISH 包的应用消息的所有权后,必须用包含传入 PUBLISH 包的包标识符的 PUBREC 包来进行响应。
在接收方收到相应的 PUBREL 包之前,它必须对每一个具有和传入 PUBLISH 包相同包标识符的后续 PUBLISH 包发送一个 PUBREC 包来进行确认。它绝不能容许把一个内容重复的消息传给任何位于下游的接收方。
在收到发送方发来的 PUBREL 包之后,它必须通过发送包含与 PUBREL 相同的包标识符的 PUBCOMP 包来响应。
发送 PUBCOMP 包后,接收方必须把任何后续的具有与传入 PUBLISH 包相同包标识符的后续 PUBLISH 包视为全新的发布消息。
MQTT 控制数据包的详述
控制包 | 发送方向 | 描述 |
---|---|---|
CONNECT | 客户端 -> 服务端 | 客户端请求与服务端建立连接 |
CONNACK | 服务端 -> 客户端 | 连接成功建立 |
PUBLISH | 客户端 -> 服务端 / 服务端 -> 客户端 | 发布消息 |
PUBACK | 客户端 -> 服务端 / 服务端 -> 客户端 | 收到发布消息的确认 |
PUBREC | 客户端 -> 服务端 / 服务端 -> 客户端 | 收到发布消息(Qos 2 的第二次握手) |
PUBREL | 客户端 -> 服务端 / 服务端 -> 客户端 | 不再发布消息(Qos 2 的第三次握手) |
PUBCOMP | 客户端 -> 服务端 / 服务端 -> 客户端 | 消息发布的完结(Qos 2 的第四次握手) |
SUBSCRIBE | 客户端 -> 服务端 | 客户端请求订阅某主题 |
SUBACK | 服务端 -> 客户端 | 订阅操作成功 |
UNSCBSCRIBE | 客户端 -> 服务端 | 客户端请求取消订阅某主题 |
UNSCBACK | 服务端 -> 客户端 | 取消订阅操作成功 |
PINGREQ | 客户端 -> 服务端 | PING 请求 |
PINGRESP | 服务端 -> 客户端 | PING 响应 |
DISCONNECT | 客户端 -> 服务端 | 客户端断开了与服务端的连接 |
参考文献
OASIS 文档:
有些内容转自 BB Smartworx 和 IBM Developer Work。
本文的版权归 Tnecesoc 所有,如需转载请联系作者。