热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

物联网协议——MQTT与ROS

 0x00 写在前面本文仅介绍MQTT与ROS两种协议的基本概念并做横向对比,不会涉及各个协议的高级特性,两种协议的本地搭建方式也会在下一篇文章中予以阐述,以下高级特性若读者有兴趣可以自行收集资料了解

 

0x00 写在前面

本文仅介绍MQTT与ROS两种协议的基本概念并做横向对比,不会涉及各个协议的高级特性,两种协议的本地搭建方式也会在下一篇文章中予以阐述,以下高级特性若读者有兴趣可以自行收集资料了解。(也不排除我后面会发相关文章,老鸽子了)

MQTT高级特性:保留消息(Retained Messages)、遗嘱消息(Last Will and Testament)、会话保持(Keep Alive)、客户端托管(Client Take-over)、链路保密(TLS)、访问控制(ACL)。

ROS高级特性:参数服务器(Parameter Server)、服务端-客户端方式。

 

0x01 概述

MQTT是基于发布-订阅模式的C/S架构消息传输协议,它轻量、开放、简单且易于实施。这些特性使其非常适合在特殊的受限情况下使用,例如用于机器对机器(M2M)和物联网(IoT)中的通信,这些环境中由于存储空间和网络带宽非常宝贵因此需要代码体积尽量小,网络协议尽量简单,MQTT正好满足这两点要求。

ROS是用于编写机器人软件的灵活框架,它是工具、库和约定的集合,旨在简化跨各种机器人平台创建复杂而强大的机器人行为的任务。

 

0x02 关于订阅者-发布者模式



观察者模式(Observer Pattern)

在继续说订阅者-发布者模式之前,有必要提出观察者模式的概念,观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新。观察者模式属于行为型模式,行为型模式关注的是对象之间的通讯,观察者模式就是观察者和被观察者之间的通讯。

观察者模式有一个别名叫“发布-订阅模式”,或者说是“订阅-发布模式”,订阅者和订阅目标是联系在一起的,当订阅目标发生改变时,逐个通知订阅者。我们可以用报纸期刊的订阅来形象的说明,当你订阅了一份报纸,每天都会有一份最新的报纸送到你手上,有多少人订阅报纸,报社就会发多少份报纸,报社和订报纸的客户就是上面文章开头所说的“一对多”的依赖关系。


发布-订阅模式(Pub-Sub Pattern)



简介

上面提到发布-订阅模式是观察者模式的一个别称,但是经过时间的沉淀,这个模式已经慢慢独立于观察者模式,成为另外一种不同的设计模式。

在现在的发布-订阅模式中,称为发布者的消息发送者不会将消息直接发送给订阅者,这意味着发布者和订阅者不知道彼此的存在。在发布者和订阅者之间存在第三个组件,称为消息代理或调度中心或中间件,它维持着发布者和订阅者之间的联系,过滤所有发布者传入的消息并相应地分发它们给订阅者。

举一个例子,你在微博上关注了A,同时其他很多人也关注了A,那么当A发布动态的时候,微博就会为你们推送这条动态。A就是发布者,你是订阅者,微博就是调度中心,你和A是没有直接的消息往来的,全是通过微博来协调的(你的关注,A的发布动态)。


特点

使用发布订阅模式可以对发布者和订阅者进行解耦,主要表现为:


  • 空间解耦:对于任意的发布者与订阅者,他们事先不需要知道彼此的存在,甚至不需要知道彼此的IP和端口。

  • 时间解耦:对于任意的发布者与订阅者,他们不需要同时运行。

  • 同步解耦:在通信发生时,他们彼此正在进行的任务不需要进行中断。

 

0x03 关于MQTT协议



协议特点

MQTT协议在实际实现中就整体使用了发布者-订阅者模式,那么依据发布者-订阅者模式的特点,MQTT同样实现了这三个特点:


  • 空间解耦:对于使用了MQTT协议的系统,每一个发布者或订阅者只需要知道消息代理(或称为MQTT主服务器)的IP/端口就可以进行消息的发布与接收。

  • 时间解耦:尽管大多数情况下使用MQTT协议的系统在进行消息传递时都是实时的,但是在必要的情况下消息代理可以为离线的客户端储存消息。必要的情况应当满足以下两个条件:

    1. 客户端曾经连入过消息代理并建立过持久化会话

    2. 需要储存的消息的QoS(服务质量)应当大于0



  • 同步解耦:MQTT协议的系统的绝大多数客户端库都是异步的,他们的函数模式基本都是基于callback模式的,因此在其发布消息或等待消息时不会发生流程的阻塞。但是,MQTT提供了部分同步方法,如果某些特定消息必须进行同步,那么可以使用这些方法来达到理想的同步效果。

PS:当客户端与消息代理连接时,可以额外指定持久化会话标识,消息代理接收到后会与此客户端建立持久化会话而非临时会话,与临时会话的区别只要在于,在持久化会话中,消息代理会帮客户端保存特定的信息。


话题-Topic



基本概念

根据上面的描述,我们可以很轻易地画出在MQTT中消息传递的拓扑图:

可以看到,我们在拓扑中引入了话题(Topic)的概念,对于MQTT系统,其通常采用基于话题的消息过滤机制,即消息代理会依据话题名来进行消息的分发。


编写规范

在MQTT中,话题名是由一串UTF-8编码的字符串组成的,例如:

kingdom/phylum/class/order/family/genus/species(界门纲目科属种)

这同时也是一个多级主题的示例,在MQTT中,允许存在多级话题,可以向任何一级发布消息,每一个话题级别由/分割。

对于主题名,有如下规则:


  1. 每个主题至少包含一个字符。

  2. 主题允许包含空格而不会被截断。


  3. 大小写敏感

  4. 单个/是一个有效的话题。

  5. 发布消息时不允许包含通配符作为话题名。

  6. 发布消息时不允许使用$开头的主题名。

对于这些规则,有以下几点补充说明:


  1. 不要使用前导正斜杠。例如/kingdom/phylum,尽管这也是合法的主题名,但是此时kingdom的主题层级不再是顶级主题,通常这会导致混乱的发生。

  2. 不要使用空格作为主题名的一部分。例如shui guo/xi gua,尽管这也是合法的主题名,但是通常空格会导致可读性下降,进而导致混乱的发生。

  3. 在主题名中加入UID。例如0df8827c-2af2-4710-84f3-b35f30f177f5/data,尽管这并非强制需求,但是配合ACL规则,这将可以保证良好的可读性,并且避免敏感信息的泄露。

  4. 非必要不要订阅#。这将导致本地的消息负载过大进而导致宕机,如确有需要记录所有消息(例如实现了一个logger),可以考虑基于MQTT做功能扩展实现负载均衡。

  5. 不要操作$开头的主题。这部分主题由消息代理保留,一般用于消息代理保存相关统计信息。例如:

    $SYS/broker/clients/connected
    $SYS/broker/clients/disconnected
    $SYS/broker/clients/total
    $SYS/broker/messages/sent
    $SYS/broker/uptime




通配符

订阅者在订阅话题时,除了可以使用完整的话题名之外,还可以使用通配符进行话题的订阅。

通配符分为两种,分别是单层通配符(+)和多层通配符(#):


  • 单层通配符(+):单层通配符可以替代主题名中的任意一个层级用来指代本层级的所有话题层级名,单层通配符前后必须是正斜杠/(单层通配符处于主题名末尾时除外)。例如使用kingdom/phylum/+/order作为主题名订阅时,匹配结果如下| Topic | Status |
    | :—————————————————: | :——: |
    | kingdom/phylum/class/order | Yes |
    | kingdom/phylum/aaaaa/order | Yes |
    | kingdom/phylum/aaaaa/bbbbb | No |
    | kingdom/bbbbbb/aaaaa/order | No |
    | kingdom/phylum/aaaaa/bbbbb/order | No |

  • 全局通配符(#):全局通配符必须是主题名的最后一个字符,且全局通配符之前必须是正斜杠/(主题名只有#的情形除外)例如使用kingdom/phylum/#作为主题名订阅时,匹配结果如下| Topic | Status |
    | :———————————————: | :——: |
    | kingdom/phylum/class/order | Yes |
    | kingdom/phylum/aaaaa/order | Yes |
    | kingdom/phylum/aaaaa/bbbbb | Yes |
    | kingdom/bbbbbb/aaaaa/order | No |
    | kingdom/phylum/aaaaa/bbbbb/order | Yes |

    特别的,当使用#作为整个主题名时,此订阅者将会收到所有发给消息代理的消息。




与消息队列的区别



  • 消息队列机制中,消息被消息队列保存,直到使用者将其接收使用(消耗)为止,这点MQTT与之相同,就像没有订阅者的话题一样。

  • 消息队列机制中,每一条消息都仅由一个客户端使用并处理,这将把负载均衡到每个客户端,而在MQTT系统中,所有订阅了此Topic的订阅者都将获取此消息。

  • 队列是命名的,必须首先显式创建后才能对其写入以及读取,而MQTT拥有隐式创建Topic的能力,即,当我们向MQTT的某个Topic发布消息时,若此时Topic不存在,消息代理会自动的创建此Topic。



服务质量-QoS

MQTT中有三个服务质量级别,服务质量将直接影响消息传递的可靠性以及资源开销。


QoS 0 – 尽最大努力交付

这个级别是最低的服务质量级别,只保证尽最大努力,此消息在发送方端不做存储,且不要求接收方发送确认,不会进行任何重发操作,可靠性与TCP协议相同,资源开销最低。


QoS 1 – 确保交付

这个级别是中等的服务质量级别,只保证消息能被接收方能接收到消息而不管接收方接收到几次消息,资源开销中等,发送方应当保存一份消息至本地,直到接收到接收方发送来的PUBACK消息,当等待时间超过阈值,即重发消息。一般来说,若消息接受方是客户端(例如,订阅者),它应当立即处理此消息并回复PUBACK消息;若消息接收方是消息代理,它应当立即依据话题名或其他消息过滤机制进行下一步分发并回复PUBACK消息。

此外,发送方发送的消息包中有DUP标志位,当这个消息包是重发的消息包时将会把这个标志位置位,但是,无论此标志位是否置位,接收方在收到后都会发起确认,此标志位只用于内部的目的,对于消息代理和客户端都是透明的。


QoS 2 – 仅一次交付

这个服务级别是最高服务级别,这是最安全的级别但同时也是最慢的服务级别,在此种模式下可以确保接受方接收且仅接受一次目标消息。发送方和接收方之间至少有两个请求/响应流(四部分握手)来提供保证,发送者和接收者使用原始发布消息的数据包标识符来协调消息的传递。

当接收方从发送方获得QoS 2级别的数据包时,它会相应地处理发布消息,并向发送方回复PUBREC数据包,如果发送方直到阈值时间结束也没有从接收方收到PUBREC数据包,它将再次发送带有DUP标志的数据包,直到收到确认为止。

一旦发送方从接收方接收到PUBREC数据包,发送方就可以安全地丢弃初始的数据包。发送方存储来自接收方的PUBREC数据包,并以PUBREL数据包作为响应 。

接收者获得PUBREL数据包后,它可以丢弃所有存储的数据包并用PUBCOMP数据包应答(发送者接收到PUBCOMP时也是如此)。在接收方完成处理并将PUBCOMP数据包发送回发送方之前,接收方将存储对原始数据包的标识符并将其锁死。此步骤很重要,可以避免再次处理该消息。发送方收到PUBCOMP数据包后,将对之前锁死的数据包进行解锁操作,此时已发布消息的数据包标识符将变为可用。

此时,QoS 2级别的消息交付流程结束,如果任何一个数据包在途中丢失,则发件人有责任在合理的阈值时间内进行消息的重传。


局限性



降级攻击

对于MQTT系统中最重要的发布者和订阅者而言,实际在进行订阅动作与发布动作时的QoS级别可能是不同的。例如,客户端A是消息的发布者,客户端B是消息的订阅者,如果客户端B以QoS 1订阅Topic,而客户端A以QoS 2发布信息到Topic,那么代理最终会以QoS 1的服务质量将消息传送到客户端B处,而且客户端B将有可能会收到多次消息。


数据标识符并不唯一

正像上文所提到的,数据传输时的数据标识符并不是唯一的,它只会在数据传输时被消息代理临时锁死(QoS 0级别时除外),一旦整个流程结束此标识符将会被释放,因此官方给定的数据标识符范围是0~65535,官方认为在不进行客户端的交互时,发送超过65535条消息是不现实的。

 

0x04 关于ROS”协议”



系统特点

与MQTT协议不同,ROS 是一个适用于机器人的开源的元操作系统。它提供了操作系统应有的服务,包括硬件抽象,底层设备控制,常用函数的实现,进程间消息传递,以及包管理。它也提供用于获取、编译、编写、和跨计算机运行代码所需的工具和库函数。在某些方面ROS相当于一种“机器人框架(robot frameworks)。ROS实现了几种不同的通信方式,包括基于同步RPC样式通信的服务(services)机制,基于异步流媒体数据的话题(topics)机制以及用于数据存储的参数服务器(Parameter Server)。


  • 小型化:ROS尽可能设计的很小 — 我们不封装您的 main() 函数 — 所以为ROS编写的代码可以轻松的在其它机器人软件平台上使用。 由此得出的必然结论是ROS可以轻松集成在其它机器人软件平台:ROS已经可以与OpenRAVE,Orocos和Player集成。

  • ROS不敏感库:ROS的首选开发模型都是用不依赖ROS的干净的库函数编写而成。

  • 语言独立:ROS框架可以简单地使用任何的现代编程语言实现。我们已经实现了Python版本,C++版本和 Lisp版本。同时,我们也拥有Java 和 Lua版本的实验库。

  • 方便测试:ROS内建一个了叫做rostest的单元/集成测试框架,可以轻松安装或卸载测试模块。

  • 可扩展:ROS可以适用于大型运行时系统和大型开发进程。



话题-Topic



  • ROS的话题与MQTT的话题不同,它并不是一个单纯的存储位置,它拥有实际的消息处理能力,我们每一个接入ROS master server(此处担任消息代理)的PC都是一个节点,而每一个节点都拥有若干个Topic,产生订阅关系时,订阅者与发布者都是话题。

  • 由于ROS并未实现标准的订阅者-发布者模式,因此在ROS系统中的订阅者与发布者事实上没有进行解耦,所有的节点都可以向任意话题发布消息,同时,所有的节点可以订阅任意的话题。

  • ROS的话题机制不支持通配符机制,它的话题名不应包含任何特殊字符。

 

0x05 二者对比



  1. 首先,ROS是一个成型的系统,而MQTT只是一种通信的协议。

  2. ROS除了支持Pub-Sub通信外,还支持C-S通信。

  3. MQTT协议的所有消息都经过消息代理的转发,只需要一个单一出口,代理管理所有的消息处理与分发。而ROS的消息由话题自己处理,其主服务器虽然担任消息代理,但是其仅管理所有Topic的IP与端口,实际的消息处理由Topic自行进行。

  4. 对于消息传输,MQTT协议更加健全,包括引入了服务质量以及访问控制等安全性概念,相比之下,ROS系统的鉴权以及链路保护均不完善,但是由于其比MQTT更轻量,二次开发难度更低,也有不少厂商开始青睐此系统,应当引起重视。(事实上,ROS安全性已经在ROS2中有了很大的改善,但是由于迭代难度较大,部分API的约定与ROS不一致导致许多产商并不愿意去进行版本的迭代)

 

0x06 参考链接

【原】发布订阅模式与观察者模式 – hf_872914334


推荐阅读
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了Windows操作系统的版本及其特点,包括Windows 7系统的6个版本:Starter、Home Basic、Home Premium、Professional、Enterprise、Ultimate。Windows操作系统是微软公司研发的一套操作系统,具有人机操作性优异、支持的应用软件较多、对硬件支持良好等优点。Windows 7 Starter是功能最少的版本,缺乏Aero特效功能,没有64位支持,最初设计不能同时运行三个以上应用程序。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 本文介绍了如何使用iptables添加非对称的NAT规则段,以实现内网穿透和端口转发的功能。通过查阅相关文章,得出了解决方案,即当匹配的端口在映射端口的区间内时,可以成功进行端口转发。详细的操作步骤和命令示例也在文章中给出。 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • Python瓦片图下载、合并、绘图、标记的代码示例
    本文提供了Python瓦片图下载、合并、绘图、标记的代码示例,包括下载代码、多线程下载、图像处理等功能。通过参考geoserver,使用PIL、cv2、numpy、gdal、osr等库实现了瓦片图的下载、合并、绘图和标记功能。代码示例详细介绍了各个功能的实现方法,供读者参考使用。 ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • 本文介绍了在mac环境下使用nginx配置nodejs代理服务器的步骤,包括安装nginx、创建目录和文件、配置代理的域名和日志记录等。 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
author-avatar
双子汐晨_312
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有