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

news2024/12/23 22:28:17

一、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"的消息。

测试成功

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

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

相关文章

计算字符串的长度几种方法 | 递归 | 指针减指针 | 计数器 | C语言 | 详解 | 期末考试必看!!!

一&#xff0c;使用 递归 计算 字符串 的 长度 1&#xff0c;题目描述 2&#xff0c;分析题目 Ⅰ&#xff0c;题目中要求除了函数的形参&#xff0c;函数中不能够使用多余的变量&#xff08;这是比较苛刻的要求&#xff09;。 Ⅱ&#xff0c;根据此&#xff0c;很自然的…

C++正则表达式全攻略:从基础到高级应用

C正则表达式全攻略&#xff1a;从基础到高级应用 一、基础知识二、正则表达式的基本匹配三、C中使用正则表达式四、高级正则表达式五、实践示例六、性能优化6.1、编译正则表达式6.2、避免过度使用回溯6.3、优化匹配算法 七、总结 一、基础知识 正则表达式是一种用于匹配、搜索…

C#【必备技能篇】cmd重定向

文章目录 一、实现目的二、工程1&#xff1a;Test.cs代码三、工程2&#xff1a;MainConsoleApp.cs代码四、测试结果 一、实现目的 通过MainConsoleApp.exe向Test.exe中输入参数&#xff0c;并将结果返回到MainConsoleApp.exe 二、工程1&#xff1a;Test.cs代码 using System…

机器学习-生存分析:如何基于随机生存森林训练乳腺癌风险评估模型?

一、 引言 乳腺癌是女性最常见的恶性肿瘤之一&#xff0c;也是全球范围内女性死亡率最高的癌症之一。据统计&#xff0c;每年全球有超过200万人被诊断为乳腺癌&#xff0c;其中约60万人死于该疾病。因此&#xff0c;乳腺癌的早期诊断和风险评估对于预防和治疗乳腺癌具有非常重要…

计算机毕业论文内容参考|基于Java的超市管理系统的设计与实现

文章目录 摘要:前言绪论1课题背景2国内外现状与趋势3课题内容相关技术与方法介绍系统分析系统设计系统实现系统测试总结与展望后续工作展望摘要: 本文详细介绍了基于Java的超市管理系统的设计与实现。该系统采用Java语言和常用的开发框架,实现了超市的进货、销售、库存等日…

[Flutter]WindowsOS中相关配置

Flutter项目在Windows平台上如何配置 目录 Flutter项目在Windows平台上如何配置 写在开头 正文 1、OS准备 2、编译环境准备 ① 下载AndroidStudio ② 下载dart ③ 下载flutter ④ 下载并安装VS ⑤ 在AS中配置dart和flutter 3、配置中遇到的问题 写在结尾 写在开头…

2024年编程学习规划:掌握编程技能的最佳路线

如果大家感感兴趣也可以去看&#xff1a; &#x1f389;博客主页&#xff1a;阿猫的故乡 &#x1f389;系列专栏&#xff1a;JavaScript专题栏 &#x1f389;ajax专栏&#xff1a;ajax知识点 &#x1f389;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 文章…

经典卷积神经网络-VGGNet

经典卷积神经网络-VGGNet 一、背景介绍 VGG是Oxford的Visual Geometry Group的组提出的。该网络是在ILSVRC 2014上的相关工作&#xff0c;主要工作是证明了增加网络的深度能够在一定程度上影响网络最终的性能。VGG有两种结构&#xff0c;分别是VGG16和VGG19&#xff0c;两者并…

JRT代码结构调整和示例

之前一直没建表专门使用ORM的api&#xff0c;做模板设计器需要建表&#xff0c;就一边开发设计器一般测试和调整ORM的api&#xff0c;只有做业务才能知道哪些api使用别扭&#xff0c;写了设计器之后改进了ORM的api以方便业务操作数据库。新写法差不多是ORM操作数据库的稳定api了…

【jmeter】将上一个请求的结果作为下一个请求的参数

1、简介 ApacheJMeter是Apache组织开发的基于Java的压力测试工具。用于对软件做压力测试&#xff0c;它最初被设计用于Web应用测试但后来扩展到其他测试领域。它可以用于测试静态和动态资源例如静态文件、Java小服务程序、CGI脚本、Java对象、数据库&#xff0c;FTP服务器&…

Think-on-Graph—基于知识图谱的LLM推理

文章目录 背景动机LLM模型存在的问题LLM ⊕ \oplus ⊕KG范式的局限性 LLM ⊗ \otimes ⊗KG范式&#xff08;Think on Graph&#xff0c;ToG&#xff09;LLM ⊗ \otimes ⊗KG范式的过程ToG的三个阶段初始化实体提取关系及实体探索推理 例子及效果相关结论搜索深度和波束宽度对To…

Centos安装Kafka(KRaft模式)

1. KRaft引入 Kafka是一种高吞吐量的分布式发布订阅消息系统&#xff0c;它可以处理消费者在网站中的所有动作流数据。其核心组件包含Producer、Broker、Consumer&#xff0c;以及依赖的Zookeeper集群。其中Zookeeper集群是Kafka用来负责集群元数据的管理、控制器的选举等。 由…

大模型通向AGI,腾讯云携手业界专家探索创新应用新风向

引言 一年过去&#xff0c;ChatGPT 引发的 AGI 热潮丝毫未减。只是相对于最初推出时掀起的全民大模型热&#xff0c;如今关于该如何落地的讨论更多了起来。 随着算力、数据库、大数据等底层技术的发展&#xff0c;大模型的建设与在各个领域的应用正在加速推进&#xff0c;那么…

SaleSmartly获得了Meta Business Partners认证徽章

近日&#xff0c;SaleSmartly通过了社交网络服务巨头Meta在消息领域的Business Partners认证&#xff0c;这项权威且重要的认证进一步证实了SaleSmartly在消息管理领域的卓越实力和卓越成果。 Meta是一家美国互联网公司&#xff0c;旗下拥有Facebook、Instagram、WhatsApp等社交…

YOLOv8改进 | 注意力篇 | ACmix自注意力与卷积混合模型(提高FPS+检测效率)

一、本文介绍 本文给大家带来的改进机制是ACmix自注意力机制的改进版本&#xff0c;它的核心思想是&#xff0c;传统卷积操作和自注意力模块的大部分计算都可以通过1x1的卷积来实现。ACmix首先使用1x1卷积对输入特征图进行投影&#xff0c;生成一组中间特征&#xff0c;然后根…

项目引入Jar包的几种方式

目录 背景 方式一 前提 创建一个jar包 使用 方式二 背景 通常情况下&#xff0c;使用SpringBoot框架开发项目的过程中&#xff0c;需要引入一系列依赖&#xff0c;首选的就是在项目的 pom.xml 文件里面通过Maven坐标进行引入&#xff08;可以通过Maven的坐标引入jar包的前…

设计模式之工厂设计模式【创造者模式】

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

今天用vite新建的vue3的项目 启动遇到报错

UnhandledPromiseRejectionWarning: SyntaxError: Unexpected token ??at Loader.moduleStrategy (internal/modules/esm/translators.js:145:18) (Use node --trace-warnings ... to show where the warning was created) (node:30304) UnhandledPromiseRejectionWarning: U…

数据库索引、三范式、事务

索引 索引&#xff08;Index&#xff09;是帮助 MySQL 高效获取数据的数据结构。常见的查询算法,顺序查找,二分查找,二叉排序树查找,哈希散列法,分块查找,平衡多路搜索树 B 树&#xff08;B-tree&#xff09;。 常见索引原则有 选择唯一性索引&#xff1a;唯一性索引的值是唯…

听GPT 讲Rust源代码--library/panic_unwind

File: rust/library/panic_unwind/src/seh.rs 在Rust源代码中&#xff0c;rust/library/panic_unwind/src/seh.rs这个文件的作用是实现Windows操作系统上的SEH&#xff08;Structured Exception Handling&#xff09;异常处理机制。 SEH是Windows上的一种异常处理机制&#xff…