基于JavaScript的MQTT实时通信应用开发指南

MQTT 协议入门与实践:使用 JavaScript 构建实时通信应用

1. 什么是 MQTT?

MQTT(Message Queuing Telemetry Transport)是一种轻量级的 发布/订阅(Pub-Sub) 消息协议,专为低带宽、高延迟或不稳定的网络环境设计。它广泛应用于物联网(IoT)、即时通讯、远程监控等场景。

核心特性:

  • 低开销:协议头部仅 2 字节,适合嵌入式设备。
  • 发布/订阅模型:解耦消息生产者和消费者。
  • 多 QoS 支持:提供 3 种消息传递质量等级。
  • 支持遗嘱消息:客户端异常断开时通知其他设备。

2. MQTT 基础概念

术语说明
Broker消息代理服务器(如 Mosquitto、EMQX),负责转发消息。
Topic消息的分类标识(如 sensor/temperature),支持通配符 +#
QoS消息质量等级:
0 - 最多一次(可能丢失)
1 - 至少一次(可能重复)
2 - 恰好一次(可靠但开销大)
Client发布或订阅消息的设备或应用。

3. 实战:用 JavaScript 实现 MQTT 客户端

以下是一个基于 mqtt.js 库的封装类(代码来自提供的 mqttClient.js):

功能亮点:

  1. 自动重连机制
    this.client.on('reconnect', () => {if (++this.reconnectCount >= this.maxReconnectAttempts) {this.client.end(); // 超过最大重试次数后放弃}
    });
    
  2. Promise 封装连接
    connect() {return new Promise((resolve, reject) => {this.client.on('connect', resolve);this.client.on('error', reject);});
    }
    
  3. 安全的资源释放
    disconnect() {if (this.client?.connected) {this.client.end(); // 避免内存泄漏}
    }
    

使用示例:

const mqttClient = new MqttClient('mqtt://broker.emqx.io');// 连接并订阅
mqttClient.connect().then(() => {mqttClient.subscribe('home/sensor', (topic, message) => {console.log(`[${topic}] ${message}`);});// 发布消息mqttClient.publish('home/light', 'ON');
});// 页面卸载时断开连接
window.addEventListener('beforeunload', () => mqttClient.disconnect());

4. 常见问题与优化建议

❗ 问题 1:消息重复接收

原因:QoS 1 可能导致重复消息。
解决:在回调函数中实现幂等处理(如消息 ID 去重)。

❗ 问题 2:连接不稳定

优化

  • 增加心跳检测(keepalive 参数)。
  • 使用 WebSocket 替代 TCP(适用于浏览器环境):
    new MqttClient('ws://broker.emqx.io:8083/mqtt');
    

❗ 安全问题

  • 避免硬编码密码,使用环境变量:
    new MqttClient(import.meta.env.VITE_MQTT_URL, '', '用户名', '密码');
    
  • 启用 TLS 加密(mqtts://)。

5. 扩展应用场景

  • 🌡️ 物联网传感器数据采集(如温度上报)
  • 📱 实时聊天应用(Topic 对应聊天室)
  • 🚨 设备异常监控(通过遗嘱消息通知离线事件)

结语

MQTT 的轻量级和灵活性使其成为实时通信的理想选择。通过本文的封装类,你可以快速集成 MQTT 到你的 JavaScript 项目中。建议进一步探索:

  • MQTT 5.0 新特性
  • 服务端搭建(如 EMQX)

提示:在浏览器中使用时,需注意跨域问题和 WebSocket 支持!


完整代码示例

/*** * 调用方式如下* const mqttClient = new MqttClient('mqtt://your-broker-url');* mqttClient.connect();* mqttClient.subscribe('your/topic', (topic, message) => {* console.log(`${topic}: ${message}`);* });* * 在页面销毁时断开连接,释放资源(防止骂娘)* mqttClient.disconnect();* */import mqtt from 'mqtt';// 定义MqttClient类
class MqttClient {// 构造函数,接收broker的URL和客户端ID(可选)constructor(brokerUrl, clientId = `client-${Math.random().toString(16).substr(2, 8)}`, username = '', password = '') {this.brokerUrl = brokerUrl; // 存储broker的URLthis.clientId = clientId; // 存储客户端ID,如果没有提供则生成一个随机的this.client = null; // 初始化mqtt客户端为nullthis.reconnectCount = 0; // 添加重连计数器this.maxReconnectAttempts = 5; // 设置最大重连次数this.username = username;this.password = password;}/*** 连接到MQTT broker的方法,返回Promise*/connect() {return new Promise((resolve, reject) => {const options = {clientId: this.clientId,clean: true,connectTimeout: 4000,reconnectPeriod: 1000,username: this.username, // 添加用户名配置password: this.password // 添加密码配置};this.client = mqtt.connect(this.brokerUrl, options);this.client.on('connect', () => {console.log('M_connected');this.reconnectCount = 0; // 连接成功后重置计数器resolve(true);});this.client.on('error', (error) => {console.error('M_error:', error);reject(error);});this.client.on('close', () => {console.log('M_connection closed');reject(new Error('Connection closed'));});this.client.on('offline', () => {console.log('M_client offline');reject(new Error('Client offline'));});this.client.on('reconnect', () => {this.reconnectCount++;console.log(`M_reconnecting... (Attempt ${this.reconnectCount}/${this.maxReconnectAttempts})`);if (this.reconnectCount >= this.maxReconnectAttempts) {this.client.end(); // 达到最大重连次数后断开连接reject(new Error('Max reconnection attempts reached'));}});});}/*** 订阅主题的方法,接收主题和回调函数作为参数* @param {string} topic * @param {fun} callback */subscribe(topic, callback) {this.client.subscribe(topic, { qos: 1 }, (error) => { // 使用qos 1保证消息至少被传递一次,2 网络开销较大,不推荐用 0if (error) {console.error('Subscribe error:', error);} else {// 监听消息事件,当收到消息时调用回调函数,receivedTopic与订阅主题匹配的主题this.client.on('message', (receivedTopic, message) => {callback(receivedTopic, message.toString()); // 调用回调函数处理消息});}});}/*** 发布消息到指定主题的方法,接收主题、消息和qos(可选)作为参数* @param {string} topic * @param {string|Buffer} message * @param {number} qos */publish(topic, message, qos = 1) {this.client.publish(topic, message, { qos }, (error) => { // 使用指定的qos发布消息if (error) {console.error('Publish error:', error);} else {console.log(`Published message to topic: ${topic}`);}});}/*** 断开与MQTT broker连接的方法*/disconnect() {// this.client.end();if (this.client?.connected) {this.client.end(); // 断开连接}}}export default MqttClient;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/86104.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/86104.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

React 19中如何向Vue那样自定义状态和方法暴露给父组件。

文章目录 前言一、什么是 useImperativeHandle?1.1 为什么需要 useImperativeHandle?1.2 基本语法 二、useImperativeHandle 的常见用法3.1 暴露自定义方法3.2子组件封装的弹窗关闭方法暴露给外部 注意点:总结 前言 在 React 的函数组件中&a…

Windows定时关机工具

自己设计了一款简单易用的windows定时关机工具,使用简单,使用只需两步: 1、输入设定的时间 2、点击开始计时 Ps: 1、文章顶部直接下载exe文件 2、文件设置不了免费下载,只能用云盘:定时关机工具.exe - 蓝奏云。 w…

枫清科技受邀参加2025数据智能大会

近日,由中国通信标准化协会主办,中国信通院、大数据技术标准推进委员会(CCSA TC601)承办的“2025数据智能大会”在北京隆重召开,本届大会以“Data X AI,数据燃动智能”为主题,聚焦央国企数智化转型、下一代数据治理、数…

黑马头条-数据管理平台

目录 项目介绍 功能 项目准备 技术 验证码 验证码登录 验证码登录-流程 关于token token的介绍 token的使用 个人信息设置 个人信息设置和axios请求拦截器 axios响应拦截器和身份验证失败 优化-axios响应结果 发布文章 发布文章-富文本编辑器 发布文章-频道列…

Pytorch3D 中涉及的知识点汇总

PyTorch3D 是 Facebook(现 Meta)AI 研究院(FAIR)推出的一个基于 PyTorch 的三维计算库,主要用于 3D 计算机视觉与图形学任务,如 3D 重建、渲染、点云处理、网格操作等。 下面是对 PyTorch3D 中重要涉及知识…

XML在线格式化工具

XML格式化 免费在线XML格式化与压缩工具,一键美化、校验、压缩和优化您的XML代码。支持自定义缩进、节点折叠,提升可读性,减小文件体积,加速数据传输。 https://toolshu.com/xml 本工具是一款专为处理XML(可扩展标记…

【软件系统架构】系列四:嵌入式技术

目录 一、嵌入式系统组成 (1)嵌入式处理器 (2)支撑硬件 (3)嵌入式操作系统 (4)支撑软件 (5)应用软件 二、嵌入式系统特性 三、嵌入式系统分类与分层结构 1.分类 2.嵌入式软件的五层架构深入解析 (1)硬件层(Hardware Layer) (2)抽象层(Hardware Ab…

监管报送面试回答思路和示例

在银行监管报送岗位的面试中,回答问题时需要展现出你的专业知识、实际操作经验、问题解决能力以及对监管合规的重视。以下是对各类问题的回答思路和示例: 一、专业知识类问题 1. 请简述银行监管报送的主要类型和报送频率 回答思路:分类介绍…

音视频SDK架构演进的实践与思考

“不是每一行代码都值得骄傲,但每一次迭代,都是一次更接近极致的尝试。” 从最初的数千行代码、到如今跨平台、全功能、稳定可靠的直播技术基座,大牛直播SDK走过了整整十年。十年,既是时间的刻度,更是技术沉淀与产品信…

vue.config.js配置学习

1.部署应用包时的基本 URL (baseUrl或publicPath) baseUrl在vue-cli 3.3 时弃用了,自此之后使用publicPath 默认:/ module.exports {// baseUrl:"/",publicPath: ./, ) 2.打包时输出的文件位置:outputDir 默认: dist module.…

大模型——Prompt Design

Prompt Design 为什么未来最重要的写作,不是写给人看的,而是写给AI理解的? 01|一切从一次“客服神操作”开始 前几天前,我在看一场 YC Demo Day 分享的时候,听到一个很炸裂的细节: 有个叫 Parahelp 的 AI 客服创业项目,靠一段几百行的“提示词”,打败了市面上大多数…

web布局20

在当下,可用于 Web 布局的 CSS 特性有很多,而且这个集合越来越强大。自从 Flexbox 的兼容性越来越完善,它替代了浮动布局,成为主流的布局技术。只不过,近几年来,CSS Grid 快速得到主流浏览器的支持&#xf…

数据集-目标检测系列- 餐具叉子 数据集 fork >> DataBall

数据集-目标检测系列- 餐具叉子 数据集 fork >> DataBall 贵在坚持! * 相关项目 1)数据集可视化项目:gitcode: https://gitcode.com/DataBall/DataBall-detections-100s/overview 2)数据集训练、推理相…

力扣-45.跳跃游戏 ll

题目描述 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向后跳转的最大长度。换句话说&#xff0c;如果你在 nums[i] 处&#xff0c;你可以跳转到任意 nums[i j] 处: 0 < j < nums[i] i j < n 返回到达 nums[n…

借助STL工具解题的各个技巧

目录 前言 STL容器一览 set和map如何降序构建 set和map如何插入自定义对象 multiset和multimap如何降序构建 multiset和multimap如何插入自定义对象 multi_系列如何equal_range multiset multimap unorder_multiset unorder_multimap STL容器迭代器一览 迭代器性能一览…

【Linux 设备树DTS】

Linux 设备树DTS 一、设备树概述&#xff1a;为什么它是 Linux 驱动开发的关键&#xff1f;二、设备树语法详解&#xff1a;从基础到高级2.1 基本结构&#xff1a;节点与属性2.2 数据类型与表示方式2.3 引用与别名2.4 address-cells和size-cells属性详解2.5 包含与覆盖2.6 未定…

【技巧】使用frpc安全地内网穿透ssh访问内网机器

【技巧】使用frpc安全地内网穿透ssh访问内网机器 0. 为什么需要部署 office的机器可以单向访问互联网&#xff0c;互联网无法直接访问到这台机器。有时候需要从家里通过ssh远程访问和配置。 在云服务器上部署frpc把转发ssh给需要访问的机器。 1. 互联网云服务器&#xff08;…

【Faster-Whisper】离线识别本地视频并生成字幕

【Faster-Whisper】离线识别本地视频并生成字幕 1 前言2 工具说明2.1 ffmpeg 媒体转换器2.1.1 理论简介文档 2.1.2 安装win安装python安装 2.1.3 查看查看音视频文件格式、编码 2.1.4 视频处理视频格式转换设置 视频码率裁剪视频 2.1.5 音频处理视频提取音频音频格式转换gpu加速…

开源CMS vs 闭源CMS:二次开发究竟有何不同?

在网站建设项目中&#xff0c;内容管理系统&#xff08;CMS&#xff09; 是核心基础设施。而“二次开发”则是让CMS真正适配业务需求的关键环节&#xff0c;譬如调整页面样式&#xff0c;或者新增会员体系等等。但很多人没意识到&#xff1a;选择开源CMS还是闭源CMS&#xff0c…

npm 更新包名,本地导入

package.json 更新包根目录名字&#xff0c;同时改 name 和 dependencies相关的依赖也需本地导入&#xff0c;否则无法生效 之后将改包放在你所需的项目位置&#xff0c;通过以下命令导入node_modules生效 pnpm install file:../table-ui/m-table -w防止包数据更新或丢弃&…