详解 MQTT,提供实时可靠的消息服务

leecactus0 2022-04-28 10:55:30

在以往的文章中,常常提到一种 “轻量级” 通信协议,那就是 MQTT。这篇文章将带领大家了解 MQTT 的大概内容和 JSRE 的 MQTT 模块。

 

MQTT 简介

 

MQTT 的优势

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于 发布/订阅(Publish/Subscribe)模式的 “轻量级” 通信协议,该协议构建于 TCP/IP 协议上,由 IBM 在 1999 年发布。

 

传统的基于 TCP 协议的 MQTT,对于小内存的传感器或者 IoT 设备来说,负载较为沉重,因此有基于 UDP 的 MQTT-SN(Sensor Networks),当前在传感器领域应用比较广泛,除此之外还有 MQTT over websocket 。

 

MQTT 最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通信协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。

 

MQTT 协议的主要特点:轻巧高效、可靠的消息传递、双向通信、支持不可靠的网络、可启用安全、可扩展到数以百万计的事物。在爱智的生态中,我们可以使用 Spirit 1 与各种智能设备通信打造个性化的智慧家庭,也可以与传感器、生产设备通信建造智慧园区完成工业生产。

 

MQTT 框架

MQTT 网络架构由消息服务器(Broker)、订阅者(Subscriber)、发布者(Publisher)组成,订阅者(Subscriber)和发布者(Publisher)都是 MQTT 客户端(client),发布者同时也可以订阅自己发送的消息。

 

在我们前几期的“爱智许愿树从0到完美”系列文章中,Spirit 1 就是消息服务器,我们通过 EdgerOS APP  发布愿望信息,最后通过树莓派订阅愿望信息来控制字牌和灯带。

 

MQTT 主题

发布者向服务器发布某一特定主题(Topic)的消息,然后服务器将该主题下的所有消息转发给订阅者。由于 MQTT 的 通信消息的数量级比较庞大,所以主题是通过  / 为分隔符划分不同层次,这样client 之间就可以收发自己想要的消息,主题的基本结构如下:

EdgerOS
EdgerOS/MQTT
EdgerOS/MQTT/API
EdgerOS/MQTT/Apply
EdgerOS/SDDC/Apply

订阅 EdgerOS 只能收到 EdgerOS 的主题,订阅 EdgerOS/SDDC 只能收到 EdgerOS/SDDC 的主题消息。主题也可以包含 + 和 # 两种通配符, + 代表当前层, # 代表当前层和其子层,比如订阅 EdgerOS/+ 可以收到 EdgerOS/MQTT 和 EdgerOS/SDDC 。订阅 EdgerOS/# 可以收到 EdgerOS/SDDC 、EdgerOS/MQTT/API 等等之类的消息。

 

消息 QoS

QoS 标识消息的服务级别,MQTT 规定了三种消息服务级别:

  • QoS 0:消息最多传递一次,如果 Receiver 不可用,则会丢失该消息

  • QoS 1:消息传递至少 1 次

  • QoS 2:消息仅传送一次

 

QoS 0 是一种 "fire and forget" 的消息发送模式:Sender (可能是 Publisher 或者 Broker) 发送一条消息之后,就不再关心它有没有发送到对方,也不设置任何重发机制。

 

QoS 1 包含了简单的重发机制,Sender 发送消息之后等待接收者的 ACK,如果没收到 ACK 则重新发送消息。这种模式能保证消息至少能到达一次,但无法保证消息不重复。

 

QoS 2 是最高的级别,QoS 2 设计了重发和重复消息发现机制,它需要经过两次通信才能完成:PUBLISH <-> PUBREC,PUBREL <-> PUBCOMP,保证消息到达对方并且严格只到达一次。

 JSRE 的 MQTT 模块

我们可以使用该模块创建 MQTT client,使用 TCP 和 TLS 两种安全连接方式与 Spirit 1 的 MQTT server 或 其他的 IoT cloud service 进行数据交互。MQTT 不限制传输的主题和消息内容的类型,但出于兼容性的考虑,JSRE 建议使用 JSON 数据格式进行发布和订阅。

 

API

mqtt.open(saddr[, tlsOpt[, timeout])

创建一个 MQTT client 并连接到指定的 MQTT 服务器,使用同步模式。

 

saddr :服务器套接字地址。

tlsOpt :TLS安全连接选项。默认为 undefined ,表示使用 TCP 连接。

timeout :同步连接的等待时间,单位是毫秒,默认:undefined ,表示用默认的连接超时设置。

const serAddr = socket.sockaddr('192.168.128.1', 1883)
const client = mqtt.open(serAddr, undefined, 5000)
if (!client) {
  console.log('Can not connect to broker.')
}

mqtt.mode()

获得当前进程的MQTT工作模式,有以下三种模式:

off :MQTT 未被启用。

listener :MQTT 侦听模式,不可以发布主题消息。

publisher :MQTT 可以订阅和发布消息。

 

client.close()

关闭与 MQTT server 的连接。

 

client.connect(clientOpt[, callback])

使用指定参数与  MQTT server 进行连接

clientOpt :MQTT 连接参数。

callback :连接之后的回调函数,有 client 参数,为 MQTT client 对象。

 

MQTT 连接参数如下:

client :可以被 server 识别的 client id 。

user :server 的用户名。

passwd :server 的密码。

keepalive :保持时间,以秒为单位。如果在给定的时间内,本次连接没有发送任何数据,server 将断开与 client 的连接。

will :如果这个标志被设置为  true,则消息和主题的 QoS 必须给定在 0~2 之内。

qos :如果 will 被设置为 true,消息将以给定的 QoS 值发送。

message :仅当 will 设置为 true 时才处理,当连接中断时发送该消息。

topic :只在 will 设置为 true 时处理,消息的主题。


/* MQTT Client Options */
const options = { client: 'Spirit', user: 'admin', passwd: 'password', will: false, topic: '', message: '', keepalive: 60, qos: 0 }
client.connect(options, (client) => {
  console.log('MQTT Connected!')
  // do something
})

client.isConnected()

获取 client 当前的连接状态, true 为连接, false 为未连接。

 

client.isQueued()

获取发送队列是否包含未被 server 确认的消息。

 

client.publish(topic, message[, options[, callback]])

使用指定的参数发布一条消息。

topic :消息主题。

message :消息的内容。

options :默认 qos 为0,retain 为 false 。

callback  :发布时的回调函数,参数为 error ,假如 error 为 true ,则发布失败。

qos :默认为 0 。

retain :假如为 true,server 将保留消息,以便以后订阅参数 retain 设置 为 true 的订阅者可以收到。


client.publish('topic1', 'message1')
client.publish('topic2', 'message2', { qos: 1 })
client.publish('topic3', 'message3', { qos: 1 }, (error) => {
  if (error) {
    console.log('Publish error:', error)
  }
})

client.subscribe(topic[, options[, callback]])

使用指定的参数订阅消息。

topic :订阅消息主题

options :订阅的选项,默认 qos 为0,retain 为 false 。

callback  :订阅时的回调函数,参数为 error ,假如 error 为 true ,则订阅失败。

qos :默认为 0 。

retain :假如为 true ,订阅者连接之后会收到之前 server 保留的消息。


client.subscribe('topic1', { qos: 1 })

client.unsubscribe(topic[, callback])

取消订阅消息

topic :退订信息主题。

callback :取消订阅的回调函数,参数为 error ,假如 error 为 true,则取消订阅失败。

client.unsubscribe('topic1', (error) => {
  if (error) {
    console.log('Unsubscribe error:', error)
  }
})

事件

在特定情况下,会通过客户端的事件触发器抛出以下事件:

 

connect

当 client 与 server 建立连接的时候触发。

 

disconnect

当网络链路断开,会触发这个事件。

 

close

当 server 与 client 正常断开连接的时候触发。

 

error

如果发生错误且未调用回调函数,则会发出包含错误信息的事件。如果此事件没有被侦听,则会引发异常。

 

message

当 client 从 server 接收到消息时,会触发此事件。

 

到这里已经大概讲述了 MQTT 的协议规定和 JSRE 中 MQTT 相关模块的应,想要更具体深入学习 MQTT,请结合相关文章进行思考和实践。

...全文
746 回复 打赏 收藏 举报
写回复
回复
切换为时间正序
请发表友善的回复…
发表回复
相关推荐
发帖
爱智开发者社区
加入

1497

社区成员

爱智开发者平台是一个开放的物联网平台,通过爱智世界,应用开发者可以把自己的应用分发到亿万用户的设备上,硬件开发者能够把设备能力开放给海量的开发者,让优质的应用脱颖而出,为用户提供更优秀的使用体验。
社区管理员
  • EdgerOS
  • Lumos_zbj
  • dayinfinite
帖子事件
创建了帖子
2022-04-28 10:55
社区公告
暂无公告