Web技术(七):如何使用并实现MQTT 消息订阅-发布模型?

本文详细介绍了MQTT消息订阅-发布模型,阐述了模型概念及其在物联网中的应用,如IP物联网络、操作系统进程间通信和MESH自组网。讲解了MQTT协议的起源、目标以及如何通过Mosquitto和Paho MQTT Client实践本地通信和抓包分析。此外,还探讨了MQTT报文格式、连接管理、心跳保活、消息传递和QoS级别,强调了通信安全和身份验证的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HTTP 超文本传输协议最开始是为人们互相分享HTML 超文本文件而设计的,使用Client / Server 模型交互数据,Client 向特定Server 请求获取或者提交网页数据(HTTP 的Get、Post、Put、Delete 方法),后来的HTTP/2 和QUIC 也为该目的进行了大量优化,大幅提高了有效数据的吞吐率。

到了物联网时代,需要接入网络的设备规模大幅增加,为了让物联网设备组成智能服务网络,资源受限的嵌入式物联网设备之间也需要相互通信,设备与设备之间并不需要传输像HTML 这么大的数据量,只需要传输指令、状态等少量数据。设备与设备之间的连接通信比人与设备的连接通信更加复杂,而且下发指令上传状态需要异步的双向通信协议,HTTP 就难以胜任这种应用场景了,该为物联网应用场景设计怎样的通信模型或协议呢?

一、什么是发布-订阅消息模型?

首先,我们考虑一个物联网设备既可以向某些设备发布消息(这里的消息可以是控制指令或状态数据),也可以从某几个设备中接收订阅的消息,如果消息的订阅者和发布者比较多,它们之间的耦合关系就比较复杂,后续再想增减变更订阅者或发布者会比较麻烦,HTTP 这种传统的Request / Response 模型就显得难以胜任了,我们该采用怎样的通信模型呢?

如果你熟悉Web 开发,回顾下MVVM(Model-View-ViewModel) 框架引入ViewModel 实现了View 与Model 的完全解耦,让View 和Model 的开发相互独立且更简单。如果你熟悉Linux 驱动开发,回顾下总线设备驱动模型,引入platform_bus 实现driver 和 device 的完全解耦,不仅简化了驱动开发而且大幅减少了无意义的冗余代码。

我们可以借鉴这个思路,为消息的订阅者Subscriber 和发布者Publisher 增设一个专门用来处理转发消息的代理者Broker,这就实现了订阅者和发布者的完全解耦,可以胜任比较复杂的物联网通信场景。目前比较流行的,采用订阅发布模型的物联网通信协议是MQTT,该协议的通信模型如下:
MQTT 订阅发布模型
上图中有三个角色:

  • Publisher(Client):消息发布者连接到消息代理Broker,并向其发布指定主题topic 的应用消息,每个消息都附加一个主题Topic(属于URL,可供其它设备订阅),发布者可以是传感器或开关设备等;
  • Subscriber(Client):消息订阅者连接到消息代理Broker,并向代理Broker 订阅感兴趣的主题topic,当Broker 收到订阅主题的消息后会将其分发给该topic 的订阅者,订阅者可以是执行器或显示器等;
  • Broker(Server):消息代理者同时连接订阅者和发布者,管理该网络中每个主题topic 的订阅列表,接收Publisher 发送过来的特定主题的消息,根据该消息的topic 查找其订阅列表,并将该消息发送给订阅列表中的所有Subscriber。

一个物联网设备可能同时支持向其它设备发送控制指令,且从其它设备接收状态数据,也即该设备同时承担Publisher 和Subscriber 两个角色。如果网络规模比较大,MQTT 代理Broker 需要处理的数据量比较大,可以将其放到服务端集中处理消息的接收和转发,因此Broker 可称为Server,相应的Publisher 和Subscriber 则可称为Client。

可以类比微信订阅号,每个订阅号都是一个topic,每篇文章都是一个消息,订阅号的作者是Publisher,订阅号的订阅者是Subscriber,微信后端服务器是Broker,作者在其订阅号发布一篇文章,微信服务端Broker 会将其分发给所有订阅该号的读者,作者和读者都是微信的客户。

消息发布-订阅模型中的Publisher 相当于消息的生产者,Subscriber 相当于消息的消费者,Broker 作为消息的存储分发者有点类似于总线的作用,因此这种消息发布-订阅模型也可称为消息总线,是一种很常用的消息传递模型。说到消息传递,我们很容易想到消息队列,也即消息的队列模型。消息的发布-订阅模型是为了满足更复杂的消息传递需求,在此基础上扩展而来的,二者的主要区别如下:

  • 消息的队列模型:队列这种先进先出的数据结构作为存放消息的容器(消息进出按照既定的顺序),它允许多个生产者往同一个队列发送消息(也即从队尾入队),但如果有多个消费者,某个消息只能被其中一个消费者接收(也即从队头出队),多个消费者之间是相互竞争关系。队列模型的应用比较广泛,比如任务阻塞队列、数据缓冲队列、线程安全的并发队列、线程或进程间通信的消息队列等;
    消息的队列模型
  • 消息的订阅-发布模型:存放消息的容器变成了一个个主题topic 的集合,每个topic 相当于一个消息队列,订阅者在接收消息之前需要先订阅一系列感兴趣的主题(每个topic 都生成并维护一个订阅者列表),当发布者向某个topic 发布消息后,消息代理broker 会将该消息分发给该主题的所有订阅者,同一topic 的订阅者接收到的消息是完全一样的,也即一份消息数据可以被多次消费。发布-订阅模型的应用也比较广泛,比如大量物联网设备和物联网云平台之间的消息传递、MESH 网络中各节点之间的消息传递、进程或服务之间的复杂消息传递等。
    消息的发布-订阅模型

二、订阅-发布消息模型有哪些应用?

消息的发布-订阅模型相比队列模型可以实现更复杂通信网络中消息的传递分发,该模型最大的特点就是借助Broker 实现Publisher 和Subscriber 的完全解耦,可以很方便的扩展通信网络中的节点数量。比如用于大规模物联网设备间的消息传递、MESH 自组网设备间的消息传递、嵌入式设备内进程间的消息传递等,下面逐个简单介绍。

2.1 应用于IP 物联网络中的消息传递

通过TCP/IP 协议接入互联网的嵌入式设备可以直接远程访问性能强大的服务器(现在兴起的云计算或云服务平台相当于是将服务器集群整合起来对外提供统一的计算资源或服务),消息发布-订阅模型中的Broker 需要强大的性能来传递分发大规模物联网设备之间的消息,这些云平台正好可以担任MQTT Broker 的角色,物联网设备则作为MQTT Client 可以订阅或发布特定主题的消息。

物联网设备的规模比先前移动互联网设备的规模大得多,各大互联网公司都为物联网设备的接入、管理、消息分发、数据分析等提供了相应的云服务平台(比如国内的阿里云、百度云、中国移动OneNET 等),借助IoT Cloud 和MQTT 管理物联网设备间消息传递分发的模型如下:
MQTT 用于IP网络的消息传递协议
上图左边就是作为MQTT Client 的各种物联网设备(MQTT-SN 是为Sensor Network 设计的运行在UDP 协议之上的MQTT 版本),可以订阅或发布特定主题的消息。中间是IoT Cloud,主要提供设备接入、消息分发(MQTT Broker)、数据管理等服务,为了方便开发者将物联网设备接入IoT Cloud,这些云服务商也提供了相应的SDK,将其整合进我们开发的工程代码中,配置好设备接入和身份认证所需的信息,就可以让物联网设备通过TCP/IP 接入IoT 云平台。我们可以通过PC 或手机登录IoT 云平台账户,管理我们接入的设备、构建我们的监控网络、统计分析监测数据等。

2.2 应用于操作系统进程间的消息传递

操作系统进程间的消息传递通常有消息队列、共享内存、命名管道、Socket 通信等,这几种进程间通信方式对比如下:

  • 共享内存:使用共享内存传递消息需要使用互斥锁或读写锁,保证多个进程对共享内存的互斥访问。如果有访问顺序要求,还需要使用信号量保证多个进程的有序访问;
  • 消息队列:消息队列出队入队是在临界区内进行的,因此是线程安全的,使用起来比较简单。但消息队列入队出队采用内存复制的方法,如果数据量较大会因内存复制降低数据吞吐率;
  • Socket 通信:Socket 通信需要TCP/IP 协议栈支持,还需要自己管理连接、对数据进行分割重组等,使用起来有点麻烦。Socket 通信不仅可以用于本主机内多进程间的通信,还可以跨主机、跨语言通信,比如RPC(Remote Procedure Call) 是消息队列和共享内存无法胜任的。

Socket 通信虽然可以跨主机进行RPC,但消息传递也是基于队列模型的。如果我们开发的嵌入式系统多个进程间的数据传递比较复杂,采用队列模型耦合度较高,就可以采用发布-订阅模型,让消息的生产者/发布者和消费者/订阅者完全解耦,专门有一个进程负责消息传递分发(也即MQTT Broker / 消息总线),可以很方便的支撑多进程间的复杂消息传递,通信模型如下:
嵌入式系统内多进程消息发布-订阅
在嵌入式系统内运行一个MQTT Broker 服务进程,其它需要相互传递消息的进程都只需要跟MQTT Broker 进程通信就可以了,MQTT Broker 起到了消息总线的作用,负责各进程间消息的传递分发。比如进程1 订阅主题topic1,进程2 订阅主题topic2,如果进程2 想向进程1 发送消息,只需要将消息发布到主题topic1(消息附上发布主题topic1 后发送给消息总线进程MQTT Broker),MQTT Broker 接收到该消息并将其传递给订阅该主题topic1 的进程1。

举个例子,假如需要开发一个采集大气中PM2.5、PM10 等污染物参数的环境监测系统,需要实现数据记录、UI 监控界面等功能。大气污染物数据采样硬件模块是第三方提供的,我们只需要通过该模块提供的串口协议去控制采样设备、接收采样数据即可。我们创建采样控制进程负责与采样模块的交互,UI 监控和数据记录设计成独立的进程,降低系统的复杂性,通信模型如下:
嵌入式系统多进程间消息发布-订阅示例
需要向外发送消息的进程都需要设定发布主题topic,比如采样控制进程发布主题topic_PM、UI 进程发布主题topic_UI,数据库进程和UI 进程都需要接收采样数据,只需要向MQTT Broker 进程订阅主题topic_PM 即可,UI 进程需要向采样控制进程发送指令数据,只需要让采样控制进程向MQTT Broker 进程订阅主题topic_UI 即可,UI 进程向主题topic_UI 发布指令消息,采用控制进程由于订阅了主题topic_UI 就可以顺利接收到该指令消息。

这个发布-订阅消息模型最大的好处就是解耦了消息的生产者与消费者后,可扩展性很强。假如后续需要增加一个新功能,采集大气中NO、SO2 等气体参数,只需要再增加一个第三方气体模块,创建一个气体参数进程负责跟气体模块的交互,采集的气体数据附上主题名topic_gas 发送给MQTT Broker 消息总线即可。数据库进程和UI 进程只需要新增一个订阅主题topic_gas,气体参数进程新增一个订阅主题topic_UI,即可完成新功能的添加。
嵌入式系统多进程间消息发布-订阅示例扩展
发布-订阅消息模型让消息生产者和消费者完全解耦,需要进行消息交互的进程只需要跟消息总线MQTT Broker 交互即可,这些进程间相互独立,可以由不同的人员并行开发,而且调试也更加方便。如果对通信安全要求较高,还可以配置哪些进程可接入消息总线MQTT Broker,拒绝无关进程连接上消息总线。

上面开发的环境监测设备大概率是需要接入IoT 云平台的,大量监测设备采集的数据汇总起来才更有价值,

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流云IoT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值