1,565
社区成员
在以往的文章中,常常提到一种 “轻量级” 通信协议,那就是 MQTT。这篇文章将带领大家了解 MQTT 的大概内容和 JSRE 的 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 网络架构由消息服务器(Broker)、订阅者(Subscriber)、发布者(Publisher)组成,订阅者(Subscriber)和发布者(Publisher)都是 MQTT 客户端(client),发布者同时也可以订阅自己发送的消息。
在我们前几期的“爱智许愿树从0到完美”系列文章中,Spirit 1 就是消息服务器,我们通过 EdgerOS APP 发布愿望信息,最后通过树莓派订阅愿望信息来控制字牌和灯带。
发布者向服务器发布某一特定主题(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 标识消息的服务级别,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
,保证消息到达对方并且严格只到达一次。
我们可以使用该模块创建 MQTT client,使用 TCP 和 TLS 两种安全连接方式与 Spirit 1 的 MQTT server 或 其他的 IoT cloud service 进行数据交互。MQTT 不限制传输的主题和消息内容的类型,但出于兼容性的考虑,JSRE 建议使用 JSON 数据格式进行发布和订阅。
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,请结合相关文章进行思考和实践。