使用MQTT.JS创建一个网页版的MQTT客户端

一、MQTT.JS介绍

MQTT.js 是一个开源的 MQTT 协议的客户端库,使用 JavaScript 编写,主要用于 Node.js 和 浏览器环境中。是JavaScript 环境下的 MQTT 客户端库。可以用于微信小程序、支付宝小程序等定制浏览器环境。

我们可以直接在HTML文件中进行调用:

<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>

也可以下载该文件,和HTML文件放在同一目录来进行调用:

<script src=" ./mqtt.min.js"></script>

二、网页界面设计

调用库文件后,我们需要在html中生成一些文本框,来填写一些连接服务器所需要的信息,如服务器地址,服务器端口,服务器路径,clientID,用户名,用户密码,这里在文本框中加入了默认的一些信息,如果自已有更方便测试的服务器,可以自行修改:

      服务器地址:
      <input type="text" id="host" value="ws://broker.emqx.io">
      服务器端口:
      <input type="text" id="port" value="8083">
      服务器路径:
      <input type="text" id="path" value="/mqtt">
      客  户  端  ID:
      <input type="text" id="clientID" value="">
	  用   户   名:
      <input type="text" id="user" value="test">
	  密        码:
      <input type="text" id="password" value="123">

接下来我们需要要两个按钮,用来实现连接和断开服务器功能,当按下按钮时,分别调用connectMQTT()函数和connectEND()函数:

    <button id="connectBtn" onclick="connectMQTT()">连接</button>
	<button id="disconnectBtn" disabled="disabled" onclick="connectEND()">已断开</button>

接下来,我们需要一个文本框来填写订阅的主题名称,以及一个按钮来确定订阅内容:

  <body>
	<h2>MQTT订阅</h2>
	主题:
      <input type="text" id="subtopic" value="test">
	<button onclick="subscribe_topic()">订阅</button>
  </body>

我们还需要两个文本框来填写发送的主题名称和发送的消息内容,以及一个按钮来确定发送消息:

  <body>
    <h2>MQTT消息发送</h2>
      主题:
      <input type="text" id="topic" value="test">
      消息:
      <input type="text" id="message" value="test">
	  <button onclick="sendMessage()">发送</button>
  </body>

最后,我们需要一个文本框来显示各种信息,该文本框使用<textarea>元素,该元素为一个多行的文本输入控件,在文本输入域中可以输入任意长度的文本:

  <body>
	<h1>消息框</h1>
	    <textarea id="messageTextArea" style="resize:none;" cols="80" rows="20"></textarea><br/>
  </body>

以上,界面的设计已经完成。下面我们介绍一下需要用到的MQTT.JS的API

三、MQTT.JS常用API

mqtt.connect([url], options)
连接url和选项所指定的代理,并返回客户端对象。

URL 可以是以下协议:"mqtt"、"mqtts"、"tcp"、"tls"、"ws"、"wss"、"wxs"、"alis"。URL 也可以是 URL.parse() 返回的对象,在这种情况下,两个对象会合并,也就是说,可以传递一个同时包含URL和连接选项的对象。

也可以指定一个服务器选项,内容为[{ host: 'localhost', port: 1883 }, ... ],在这种情况下,每次连接都会遍历该数组。
client.on('connect',function)
为指定事件注册一个监听器,接受一个字符串 event 和一个回调函数。
参数1:
    connect    -成功连接或重连后触发
    reconnect    -开始一个重新连接时触发
    close    -断开连接时触发
    disconnect    -从服务器接收到断开命令的数据包时触发
    offline    -客户端离线时触发
    error    -当客户端无法连接或出现解析错误时触发
    end    -调用Client.end()时触发。如果向Client.end() 传递了回调,则回调返回后会触发该事件
    message    -客户端收到发布数据包时触发
    packetsend    -客户端发送任何数据包时触发。包括published()数据包以及MQTT用于管理订阅和连接的数据包
    packetreceive    -客户端收到任何数据包时触发。包括来自订阅主题的数据包,以及MQTT用于管理订阅和连接的数据包

参数2:
    回调函数

    
Client.publish(topic, message, [options], [callback])
发布消息
参数:
    topic        -主题
    message      -消息内容
    [options]    -发布选项
    [callback]   -回调函数

Client.subscribe(topic/topic array/topic object, [options], [callback])
参数:
    topic/topic array/topic object    -要订阅的字符串主题或主题数组。也可以是一个对象,对象键是主题名称,值是 QoS,如 {'test1': {qos: 0}, 'test2': {qos: 1}}. 支持MQTT主题通配符("+"表示单层级,"#"表示多层级)
    [options]                         -是订阅的选项
    [callback]                        -回调函数
Client.end([force], [options], [callback])
参数:
    [force]        -将其设为true将立即关闭客户端,而无需等待接收到飞行中的消息。该参数为可选参数。
    [options]      -断开连接选项
    [callback]     -回调函数

这里介绍一些常用的API,如果想了解详细的API说明,可以到官方地址:https://github.com/mqttjs/MQTT.js

四、函数设计

我们需要以下几个函数来完整地实现一个MQTT客户端功能:

1、连接服务器函数

该函数从网页的文本框中获取连接服务器所需的信息,如服务器地址,服务器端口,服务器路径,clientID,用户名,用户密码,通过以上信息用mqtt.connect()函数连接服务器,连接成功后,

触发client.on('connect',function)所指向的回调函数

/* 连接服务器 */
	function connectMQTT(){
		var host = document.getElementById("host").value;			//服务器地址
        var port = document.getElementById("port").value;			//服务器端口
		var path = document.getElementById("path").value;			//服务器路径
		var clientID = document.getElementById("clientID").value;	//clientID
		var user = document.getElementById("user").value;			//用户名
		var password = document.getElementById("password").value;	//用户密码
		var url = host+':'+port+path;								//URL地址
		console.log(url);											//后台输入URL地址
		var options = {												//创建一个参数对象
			clientID:clientID,										//clientID
			username:user,											//用户名
			password:password										//用户密码
		};
		client = mqtt.connect(url,options);							//连接服务器
		console.log(client);
		console.log(client.connected);
		client.stream.on('error', function(err) {					//连接错误时触发
			console.error('Connection error:'+err);
			console.log('连接失败');
			client.end();											//关闭客户端对象
		})
		client.on('connect',function(packet){													//连接服务器后触发
			document.getElementById("connectBtn").setAttribute("disabled","disabled");			//连接按钮不可用
			document.getElementById("connectBtn").innerHTML = "已连接";							//连接按钮显示为已连接
			document.getElementById("disconnectBtn").removeAttribute("disabled","disabled");	//断开按钮设为可用
			document.getElementById("disconnectBtn").innerHTML = "断开";						//断开按钮显示为断开
			client.on('message', message_str)													//定义接收消息后触发回调函数
			var messageTextArea = document.getElementById("messageTextArea");					//textarea添加文本
			messageTextArea.value += "已连接\n"													//textarea添加文本
			console.log("已连接");																//后台输出已连接
		})
	}

2、断开消息函数

该函数利用client.end()关闭client对象

/* 断开连接服务器 */
	function connectEND(){
		if(client && client.connected){
			client.end();
			console.log("已断开连接");
			document.getElementById("connectBtn").removeAttribute("disabled","disabled");		//连接按钮设为可用
			document.getElementById("connectBtn").innerHTML = "连接";							//连接按钮显示为连接
			document.getElementById("disconnectBtn").setAttribute("disabled","disabled");		//断开按钮设为不可用
			document.getElementById("disconnectBtn").innerHTML = "已断开";						//断开按钮显示已断开
			var messageTextArea = document.getElementById("messageTextArea");					//textarea添加文本
			messageTextArea.value += "已断开\n"													//textarea添加文本
		}else{
			console.log("未连接");
		}
	}

3、发布消息函数

该函数使用client.publish()发送消息。

/* 发送消息 */
    function sendMessage() {
	    var topic = document.getElementById("topic").value;			//获取主题
        var message = document.getElementById("message").value;		//获取消息文本
		//console.log(topic);
		if(client && client.connected){
			client.publish(topic, message);							//发送消息
			console.log("已发送");
		}else{
			console.log("未连接");
		}
    }

4、订阅主题函数

该函数使用client.subscribe()来订阅一个主题。

/* 订阅主题 */
	function subscribe_topic(){
	    var topic = document.getElementById("subtopic").value;				//获取主题
        client.subscribe(topic);											//定阅主题
		var messageTextArea = document.getElementById("messageTextArea");	//获取textarea元素
		messageTextArea.value += "已定阅"+topic+"\n";						//textarea添加文本
		console.log("已订阅:"+topic);
	}

5、接收消息函数

该函数由"连接服务器函数"中的client.on('message', message_str)事件触发,当该事件触发时,调用该函数

/* 接收消息函数 */
	function message_str(topic,message){													//监听消息函数
		console.log("收到来自主题:"+topic+"的消息:"+message.toString());
		var messageTextArea = document.getElementById("messageTextArea");					//获取textarea元素
		messageTextArea.value += "收到来自主题:"+topic+"的消息:"+message.toString()+"\n"; 	//将新的文本追加到 value
	}

五、完整代码

保存为index.html

<!DOCTYPE html>
<html>
  <head>
	<!-- 可选在线mqtt.min.js文件与本地mqtt.min.js文件 -->
    <!-- <script src=" https://unpkg.com/mqtt@5.3.4/dist/mqtt.min.js"></script> -->
	<script src=" ./mqtt.min.js"></script>

  </head>
  <body>
    <h2>MQTT服务器设置</h2>
    <form>
      服务器地址:
      <input type="text" id="host" value="ws://broker.emqx.io">
      服务器端口:
      <input type="text" id="port" value="8083"> </br>
      服务器路径:
      <input type="text" id="path" value="/mqtt">
      客  户  端  ID:
      <input type="text" id="clientID" value=""> </br>
	  用   户   名:
      <input type="text" id="user" value="test">
	  密        码:
      <input type="text" id="password" value="123"> </br>
    </form>
    <button id="connectBtn" onclick="connectMQTT()">连接</button>
	<button id="disconnectBtn" disabled="disabled" onclick="connectEND()">已断开</button>
  </body>
  <body>
	<h2>MQTT订阅</h2>
	主题:
      <input type="text" id="subtopic" value="test">
	<button onclick="subscribe_topic()">订阅</button>

  </body>
  <body>
    <h2>MQTT消息发送</h2>
      主题:
      <input type="text" id="topic" value="test">
      消息:
      <input type="text" id="message" value="test">
	  <button onclick="sendMessage()">发送</button>
  </body>
  <body>
	<h1>消息框</h1>
	    <textarea id="messageTextArea" style="resize:none;" cols="80" rows="20"></textarea><br/>
  </body>
  <script>
  
	document.getElementById("clientID").setAttribute("value",randomID()); 	//生成随机clientID
	var client;																//创建一个客户端对象
/* 连接服务器 */
	function connectMQTT(){
		var host = document.getElementById("host").value;			//服务器地址
        var port = document.getElementById("port").value;			//服务器端口
		var path = document.getElementById("path").value;			//服务器路径
		var clientID = document.getElementById("clientID").value;	//clientID
		var user = document.getElementById("user").value;			//用户名
		var password = document.getElementById("password").value;	//用户密码
		var url = host+':'+port+path;								//URL地址
		console.log(url);											//后台输入URL地址
		var options = {												//创建一个参数对象
			clientID:clientID,										//clientID
			username:user,											//用户名
			password:password										//用户密码
		};
		client = mqtt.connect(url,options);							//连接服务器
		console.log(client);
		console.log(client.connected);
		client.stream.on('error', function(err) {					//连接错误时触发
			console.error('Connection error:'+err);
			console.log('连接失败');
			client.end();											//关闭客户端对象
		})
		client.on('connect',function(packet){													//连接服务器后触发
			document.getElementById("connectBtn").setAttribute("disabled","disabled");			//连接按钮不可用
			document.getElementById("connectBtn").innerHTML = "已连接";							//连接按钮显示为已连接
			document.getElementById("disconnectBtn").removeAttribute("disabled","disabled");	//断开按钮设为可用
			document.getElementById("disconnectBtn").innerHTML = "断开";						//断开按钮显示为断开
			client.on('message', message_str)													//定义接收消息后触发回调函数
			var messageTextArea = document.getElementById("messageTextArea");					//textarea添加文本
			messageTextArea.value += "已连接\n"													//textarea添加文本
			console.log("已连接");																//后台输出已连接
		})
	}

/* 断开连接服务器 */
	function connectEND(){
		if(client && client.connected){
			client.end();
			console.log("已断开连接");
			document.getElementById("connectBtn").removeAttribute("disabled","disabled");		//连接按钮设为可用
			document.getElementById("connectBtn").innerHTML = "连接";							//连接按钮显示为连接
			document.getElementById("disconnectBtn").setAttribute("disabled","disabled");		//断开按钮设为不可用
			document.getElementById("disconnectBtn").innerHTML = "已断开";						//断开按钮显示已断开
			var messageTextArea = document.getElementById("messageTextArea");					//textarea添加文本
			messageTextArea.value += "已断开\n"													//textarea添加文本
		}else{
			console.log("未连接");
		}
	}

/* 发送消息 */
    function sendMessage() {
	    var topic = document.getElementById("topic").value;			//获取主题
        var message = document.getElementById("message").value;		//获取消息文本
		if(client && client.connected){
			client.publish(topic, message);							//发送消息
			console.log("已发送");
		}else{
			console.log("未连接");
		}
    }

/* 订阅主题 */
	function subscribe_topic(){
	    var topic = document.getElementById("subtopic").value;				//获取主题
        client.subscribe(topic);											//定阅主题
		var messageTextArea = document.getElementById("messageTextArea");	//获取textarea元素
		messageTextArea.value += "已定阅"+topic+"\n";						//textarea添加文本
		console.log("已订阅:"+topic);
	}


/* 接收消息函数 */
	function message_str(topic,message){													//监听消息函数
		console.log("收到来自主题:"+topic+"的消息:"+message.toString());
		var messageTextArea = document.getElementById("messageTextArea");					//获取textarea元素
		messageTextArea.value += "收到来自主题:"+topic+"的消息:"+message.toString()+"\n"; 	//将新的文本追加到 value
	}

/* 生成随机clientID */
	function randomID(){
		return 'clientID_' + Math.random().toString(16).substr(2, 8)
	}

  </script>
</html>

六、测试代码

我们用浏览器打开该html文件

点击连接,并订阅名为"test"的主题,同时给"test"主题发送一个文本内容为"test"的消息。

测试成功

备注:在网页中使用MQTT.JS,只支持WebSocket连接选项,就是说,在网页版的客户端中,无法连接mqtt://为前缀的地址。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

静态代理、JDK动态代理、CGLIB动态代理以及JDK和CGLIB动态代理的区别

代理 什么是代理&#xff1f;两个设计原则三要素 静态代理静态代理的实现定义接口-定义行为静态代理 -> 目标角色静态代理-> 代理角色静态代理测试 特点 JDK动态代理newProxyInstance获取代理对象通过代理对象实现目标对象的功能特点 Java动态代理类中的invoke是怎么调用…

P8 RV1126推流 —— 摄像头和咪头模块初始化

前言 从本章开始我们将要学习嵌入式音视频的学习了 &#xff0c;使用的瑞芯微的开发板 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ &#x1f525; 推荐专栏2: 《Linux C应用编程&#xff08;概念类&#xff09;_C…

对偶问题的基本性质

写于&#xff1a;2024年1月3日晚 修改于&#xff1a; 原规划与对偶规划 原规划对偶规划 max ⁡ z C T X s.t. { A X ≤ b , 其中 X ( m ∗ 1 ) X ≥ 0 \begin{aligned} & \max \mathrm{z}\mathbf{C}^T \mathbf{X} \\ & \text { s.t. }\left\{\begin{array}{l}\mat…

RFID在物流、供应链管理、工业自动化等领域的广泛应用

随着物联网技术的不断发展&#xff0c;RFID&#xff08;无线射频识别&#xff09;技术作为一种自动识别和跟踪技术&#xff0c;在物流、供应链管理、工业自动化等领域得到了广泛应用。本文将介绍RFID解决方案及其应用场景。 一、RFID技术概述 RFID是一种通过无线电波通信&…

Apache的配置与应用

目录 1、Apache简介 2、Apache连接保持 3、Apache的访问控制 3.1、客户机地址限制 3.2、用户授权限制 &#xff08;1&#xff09;创建用户认证数据文件 &#xff08;2&#xff09;添加用户授权配置 &#xff08;3&#xff09;验证用户访问授权 4、Apache日志分割 4…

ALSA学习(5)——ASoC架构中的Machine

参考博客&#xff1a;https://blog.csdn.net/DroidPhone/article/details/7231605 &#xff08;以下内容皆为原博客转载&#xff09; 文章目录 一、注册Platform Device二、注册Platform Driver三、初始化入口soc_probe() 一、注册Platform Device ASoC把声卡注册为Platform …

FreeRTOS——计数型信号量知识总结及实战

1计数型信号量概念 1&#xff09;计数型信号量相当于队列长度大于1 的队列&#xff0c;因此计数型信号量能够容纳多个资源 2&#xff09;适用场景&#xff1a; 事件计数&#xff1a; 当每次事件发生后&#xff0c;在事件处理函数中释放计数型信号量&#xff08;计数值1&#x…

shell编程二

shell 脚本规范 shell脚本文件需要以.sh结尾 第一个原因&#xff0c;让别人认的这个是shell脚本&#xff0c;sh后缀编辑时有高亮显示。 拓展名后缀,如果省略.sh则不易判断该文件是否为shell脚本 ​ # 执行脚本方式 1、 sh 脚本.sh 2、 bash 脚本.sh 3、 ./脚本.sh # 需要执行权…

【C语言】数组

㊙️小明博客主页&#xff1a;➡️ 敲键盘的小明 ㊙️ ✅关注小明了解更多知识☝️ 文章目录 前言一、什么是数组&#xff1f;二、一维数组的创建和初始化2.1 一维数组的创建2.2 一维数组的初始化2.3 一维数组的使用3.3 一维数组的存储 三、二维数组的创建和初始化3.1 二维数组…

每日一练:LeeCode-503. 下一个更大元素 II (中)【单调栈】

本文是力扣LeeCode-503. 下一个更大元素 II 学习与理解过程&#xff0c;本文仅做学习之用&#xff0c;对本题感兴趣的小伙伴可以出门左拐LeeCode。 给定一个循环数组 nums &#xff08; nums[nums.length - 1] 的下一个元素是 nums[0] &#xff09;&#xff0c;返回 nums 中每个…

【大数据实战】亿级数据量: 检索一个元素是否在一个集合中 [bloom过滤器及其应用]

目录 亿级数据量: 检索一个元素是否在一个集合中 [bloom过滤器]问题描述bloom过滤器简介传统方法哈希表bloom的思路 bloom过滤器为什么快&#xff1f;bloom过滤器更加节省空间&#xff01;优缺点实际应用javagopython 亿级数据量: 检索一个元素是否在一个集合中 [bloom过滤器] …

uniapp中用户登录数据的存储方法探究

Hello大家好&#xff01;我是咕噜铁蛋&#xff01;作为一个博主&#xff0c;我们经常需要在应用程序中实现用户登录功能&#xff0c;并且需要将用户的登录数据进行存储&#xff0c;以便在多次使用应用程序时能够方便地获取用户信息。铁蛋通过科技手段帮大家收集整理了些知识&am…

python解决一维动态规划问题,寻找丑数

对于一维动态规划问题中&#xff0c;还有一个可能会经常遇到的问题&#xff0c;就是寻找丑数。 对于丑数的概念是&#xff0c;把只包含质因子2、3和5的数称作丑数&#xff08;Ugly Number&#xff09;。 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 添…

8、VS中Git使用

VS中Git使用 1.基础操作1.1 VS配置Git1.2 操作界面 2.本地库版本管理2.1 创建管理本地库2.2 暂存、存储2.3 提交2.4 版本切换 3.分支操作3.1 分支应用3.2 新建分支3.3 合并分支、解决冲突3.4 删除分支 4.远程库版本管理4.1 新建、克隆4.2 提取、拉取、推送与同步4.3 团队开发 最…

基于随机颜色反转合成和双分支学习的单模态内镜息肉分割

Single-Modality Endoscopic Polyp Segmentation via Random Color Reversal Synthesis and Two-Branched Learning 基于随机颜色反转合成和双分支学习的单模态内镜息肉分割背景难点贡献实验方法Color Reversal Strategy&#xff08;颜色反转策略&#xff09; 损失函数Thinking…

Python 箱线图的绘制(Matplotlib篇-13)

Python 箱线图的绘制(Matplotlib篇-13)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ�…

[DevOps-02] Code编码阶段工具

一、简要说明 在code阶段,我们需要将不同版本的代码存储到一个仓库中,常见的版本控制工具就是SVN或者Git,这里我们采用Git作为版本控制工具,GitLab作为远程仓库。 Git安装安装GitLab配置GitLab登录账户二、Git安装 Git官网 Githttps://git-scm.com/

【Java进阶篇】Java中Timer实现定时调度的原理(解析)

Java中Timer实现定时调度的原理 ✔️ 引言✔️JDK 中Timer类的定义✔️拓展知识仓✔️优缺点 ✔️ 引言 Java中的Timer类是用于计划执行一项任务一次或重复固定延迟执行的简单工具。它使用一个名为TaskQueue的内部类来存储要执行的任务&#xff0c;这些任务被封装为TimerTask对…

小肥柴慢慢手写数据结构(C篇)(5-2 AVL树)

小肥柴慢慢学习数据结构笔记&#xff08;C篇&#xff09;&#xff08;5-2 AVL树 目录5-5 AVL出现的原因5-5-1 平衡树5-5-2 平衡二叉树的具体案例 5-6 AVL平衡策略的讨论5-7 不使用平衡因子的实现&#xff08;黑皮书&#xff0c;训练思维&#xff09;5-8 使用平衡因子的实现&…

【RocketMQ每日一问】RocketMQ SQL92过滤用法以及原理?

1.生产端 public class SQLProducer {public static int count 10;public static String topic "xiao-zou-topic";public static void main(String[] args) {DefaultMQProducer producer MQUtils.createLocalProducer();IntStream.range(0, count).forEach(i -&g…
最新文章