一.什么是MQTT?
官方的说法:轻量级的物联网通信协议,基于发布/订阅模式,支持QoS级别,适用于低带宽、高延迟的网络环境。在MQTT中,有三个核心角色扮演着重要的角色:代理服务器(Broker)、订阅者(Subscriber)和发布者(Publisher)。
举个栗子:以B站为例,B站本身就是一个Broker,B站上有一个up主:黑马程序员,他每天都会更新发布视频,黑马程序员就是一个Publisher,而你作为B站用户觉得黑马程序员的视频讲的很不错,就关注了他,此时你这个B站用户就是Subscriber。当黑马程序员(Publisher)发布新视频的时候,你(Subscriber)就会收到B站(Broker)发送的通知。
当然,b站本身并没有使用MQTT协议,不过MQTT在我们身边依然随处可见,比如智能家居,智能城市建设,我们常用的共享单车也是使用的MQTT协议。以及在工业自动化方面,MQTT协议常被用于生产线上的设备监控、数据采集和远程控制等场景。
二.MQTT与HTTP的区别
MQTT(Message Queuing Telemetry Transport)和HTTP(HyperText Transfer Protocol)都是应用层协议,用于在客户端和服务器之间传输数据,但它们在多个方面存在显著区别。
①设计理念的区别:
MQTT是发布/订阅模式,HTTP是请求/响应模式。发布/订阅模式下,发布者(Publisher)将消息发送到某个主题(Topic),发布者发布消息后,不会直接等待订阅者的响应,而是将消息发送给消息代理(Broker),由消息代理负责将消息分发给所有订阅了该主题的订阅者。而在请求/响应模式下,请求者(Requester)发送一个请求给响应者(Responder),并等待响应者返回响应。请求者必须等待响应后才能继续执行后续操作。简而言之:MQTT是一对多,你先订阅感兴趣的主题,我有新内容就发给订阅了这个主题的所有人。而HTTP是一对一,你要什么(请求)我就给你(响应)什么。
②连接方式的区别:
MQTT支持持久连接,服务器和客户端一旦建立连接,就会保持连接状态,直到客户端或服务器主动断开。这种长连接方式减少了连接建立和断开的开销,提高了数据传输的效率。HTTP是无状态的,每次请求都需要建立新的连接。这意味着服务器不会保留之前请求的任何信息,每个请求都是独立的。虽然这种无状态性简化了服务器的设计,但在处理大量实时数据时可能会降低效率。简而言之:MQTT是办会员(持久化通讯),HTTP是单次消费。
③效率的区别:MQTT比HTTP更快,更适合设备更差,网络不好的场景。
更多区别见下图(图片来自于网络,侵删):
三.JS使用MQTT
那么我们应该如何使用JavaScript完成MQTT当中的主题订阅,消息发布呢?
我需要使用到MQTT.js库,MQTT.js 是一个为 MQTT 协议 精心打造的 JavaScript 客户端库。
注意!!!MQTT.js只用于连接 MQTT 服务器并完成主题的发布与订阅,并不能用于创建MQTT服务器!!!也不是很推荐把node作为MQTT服务器使用!
npm安装
npm install mqtt --save
yarn安装
yarn add mqtt
JavaScript代码,这里我们直接连接EMQ X 提供的 免费的公共 MQTT 服务器,该服务基于 EMQ X 的 MQTT 物联网云平台 创建,这里并不介绍如何创建MQTT服务器:
// 引入mqtt模块
const mqtt = require('mqtt')
// MQTT服务器的地址
const host = 'broker.emqx.io'
// MQTT服务器的端口
const port = '1883'
// 生成一个随机的clientId,避免连接冲突
const clientId = `mqtt_${Math.random().toString(16).slice(3)}`
// MQTT服务器的端口
const connectUrl = `mqtt://${host}:${port}`
// 使用mqtt.connect方法连接到MQTT服务器,并传入连接配置
const client = mqtt.connect(connectUrl, {
clientId, // 客户端ID
clean: true, // 是否在连接时清除session
connectTimeout: 4000, // 连接超时时间
username: 'emqx', // 连接MQTT服务器时的用户名
password: 'public', // 连接MQTT服务器时的密码
reconnectPeriod: 1000, // 重连间隔
})
// 订阅的主题
const topic = '/nodejs/FakeEnd'
// 监听连接事件
//client.on(event, callback) 方法接受两个参数:监听事件(字符串),回调函数(函数),当指定的事件发生时回调函数将被调用。
client.on('connect', () => {
console.log('链接成功喵!') // 打印连接成功的信息
// 订阅主题,并在订阅成功后打印信息
client.subscribe([topic], () => {
console.log(`成功订阅主题:'${topic}'`)
})
// 发布消息到指定的主题
//publish方法接收4个参数,第一个参数用于指定主题,第二个参数是消息的具体内容,第三个参数(可选)是一个对象,包含两个可选的属性,第四次参数是回调,如果发生错误,将传递一个error。
//qos:一个数字,表示消息的服务质量级别,MQTT 定义了三种 QoS 级别(0、1、2),它们决定了消息传递的保证程度。
//retain:一个布尔值,表示是否保留消息。如果设置为 true,消息将被存储在 MQTT 代理上,以便任何后来订阅该主题的客户端都能立即接收到这个消息(即使它们错过了原始发布)。
client.publish(topic, '测试消息喵', { qos: 0, retain: false }, (error) => {
if (error) {
console.error(error)
}
})
})
// 监听接收消息的事件
client.on('message', (topic, payload) => {
// 当接收到消息时,打印消息的主题和内容
console.log('收到消息:'+ payload.toString(),'发送该消息的主题:'+topic)
})
setTimeout(()=>{
client.publish(topic,'我又发了一条喵',{qos:0,retain:false},(error)=>{
if(error){
console.error(error)
}
})
},5000)
setTimeout(()=>{
client.publish(topic,'我又又发了一条喵',{qos:0,retain:false},(error)=>{
if(error){
console.error(error)
}
})
},8000)
//使用publish方法发送json数据
const Taffy = {
name:"永雏塔菲",
age:"30",
message:"关注塔菲喵,关注永雏塔菲谢谢喵"
}
setTimeout(()=>{
client.publish(topic,JSON.stringify(Taffy),(error)=>{
if(error){
console.error(error)
}
})
},10000)
更详细的API说明请见:MQTT.js 入门教程
附:如何运行这段代码
①首先创建一个node项目
②在你的项目的根目录随便建一个js文件,把代码贴到js文件里面
③打开终端,输入命令:node js文件名.js
④你也可以在package.json文件的scripts字段中定义脚本命令,这里nodemon能够实时监控文件系统的变化,当检测到源代码更改时,它会自动重启Node.js进程,无需开发者手动操作。
然后再命令行运行,记得把start_miao改成你自己取的名字:
npm run start_miao
⑤当然你也可以写在html里面用浏览器运行,mqtt.js在Vue、React中都可以使用,详见官方文档,这里就不再赘述了