物联网 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 所有,如需转载请联系作者。
问答
相关阅读
物联网 MQTT 服务质量级别的更多相关文章
- 物联网MQTT协议分析和开源Mosquitto部署验证
在<物联网核心协议—消息推送技术演进>一文中已向读者介绍了多种消息推送技术的情况,包括HTTP单向通信.Ajax轮询.Websocket.MQTT.CoAP等,其中MQTT协议为IBM制定 ...
- Paho -物联网 MQTT C Cient的实现和详解
概述 在文章Paho - MQTT C Cient的实现中,我介绍了如何使用Paho开源项目创建MQTTClient_pulish客户端.但只是简单的介绍了使用方法,而且客户端的结果与之前介绍的并 ...
- 纯vue3实现的svg可视化web组态编辑器。主要用于物联网mqtt实时系统图
vue就是边做这个项目边学的 代码可能有点乱 还望各位大神勿喷 如果代码对您有帮助 麻烦辛苦帮我点个star 预览地址 https://svg.yaolunmao.top 如何使用 # 克隆项目 gi ...
- MQTT物联网通讯协议入门
目录 一.MQTT协议概念 发布/订阅机制 MQTT客户端 Broker代理(服务器) MQTT消息结构 二.MQTT协议实现原理 MQTT连接 MQTT消息发布 MQTT订阅机制 MQTT订阅确认 ...
- 转战物联网·基础篇06-深入理解MQTT协议之基本术语
通过上一节我们对MQTT协议已经有了初步的印象,这一节我们开始深入的理解一下MQTT协议,介绍常用的MQTT 3.1.1版本,5.0版本后面指介绍新增部分即可.这一节我们先介绍MQTT里常用的术语 ...
- MQTT初始篇笔记整理
MQTT简介 MQTT(Message Queuing Telemetry Transport,消息队列遥测传输),基于TCP/IP 协议栈而构建,虽然叫消息队列遥测传输,但是她与消息队列毫无关系,她 ...
- 基于 WebSocket 的 MQTT 移动推送方案
WebSphere MQ Telemetry Transport 简介 WebSphere MQ Telemetry Transport (MQTT) 是一项异步消息传输协议,是 IBM 在分析了他们 ...
- 国外物联网平台(3):IBM Watson IoT
国外物联网平台(3)——IBM Watson IoT 马智 平台定位 提供全面管理的云托管服务,旨在简化并从 IoT 设备中获得价值. Watson IoT Platform 提供对 IoT 设备和数 ...
- MQTT 协议是个啥?这篇文章告诉你!
文章首发于我的公众号「程序员cxuan」,欢迎大家关注呀- 说到做到! 之前有位读者给我留言说想要了解一下什么是 MQTT 协议,顺便还把我夸了一把,有点不好意思啦. 那么读者的要求必须要满足啊,所以 ...
随机推荐
- NodeJS FTP模块使用
模块说明:https://www.npmjs.com/package/ftp 上传文件 建立连接-> 判断文件夹是否存在->创建文件夹->上传文件->End 核心代码: 连接参 ...
- redis配置文件详解及实现主从同步切换
原理:redis复制是怎么进行工作 如果设置了一个slave,不管是在第一次链接还是重新链接master的时候,slave会发送一个同步命令 然后master开始后台保存,收集所有对修改数据的命令.当 ...
- centos 安装atom 笔记
一.安装atom "To install Atom on Linux, you can download a Debian package or RPM package either fr ...
- 十分钟释疑Oracle中“小表超慢”之谜(SQL调优/SQL优化)
前几天,一个用户找到我,说查一个小表的时候非常慢,我问有多慢,他说最快也得半个小时才能出结果,有时干脆不出结果,我说小表多大,他说就几十兆,有点疑惑,让他帮忙获取了相关信息,一看就明白了,原来所谓的小 ...
- C语言第二次博客作业---分支结构 陈张鑫
一.PTA实验作业 题目1:计算分段函数[2] 本题目要求计算下列分段函数f(x)的值: 1.实验代码 int main(){double x,y; scanf("%lf",&am ...
- Linux下I/O多路转接之epoll(绝对经典)
epoll 关于Linux下I/O多路转接之epoll函数,什么返回值,什么参数,我不想再多的解释,您不想移驾,我给你移来: http://blog.csdn.net/colder2008/artic ...
- 利用python实现简单随机验证码
#!/usr/bin/env python # -*- coding:utf-8 -*- import random temp ='' for i in range(6): num = random. ...
- react基础篇入门组件
讲述一下React: 1.声明式设计-React采用声明范式,可以轻松描述应用 2.高效-React通过DOM模型,最大限度的减少dom的交互 3.灵活-React可以与已知的库或框架很好的配合 4. ...
- EasyUI中Tabs添加远程数据的方法。
tabs加载远程数据: $(function () { $("#btnquery").click(function () { if (!$("#tcontent" ...
- JaveScript内置对象(JS知识点归纳八)
1)JS自身提供的方式 用于对数据进行简便的操作,根据方法可以操作的数据类型不同,形成了不同的对象--内置对象 2)数组 a)基本操作方法--对数组进行修改 从数组最后进行操作 1)数组.push ...