一、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://为前缀的地址。