最近在uniapp打包成微信小程序的项目中第一次用到了MQTT。使用比较简单,可是仍是遇到了一些问题。在此记录一下。html
官方文档:MQTT Github前端
官方MQTT测试工具:MQTTX。测试工具使用说明python
MQTT的js文件:mqtt.min.jsgit
先上一点注意事项:github
(1) MQTT.js 一个 MQTT 协议的客户端库,用 JavaScript 编写,可用于 Node.js 和浏览器。在 Node.js 端能够经过全局安装使用命令行链接,同时还支持 MQTT ,MQTT TLS 证书链接;值得一提的是 MQTT.js 还对微信小程序有较好的支持。web
(2) MQTT能够经过三种方式链接,TCP直连, TLS和WebSocket,可是JavaScript使用 TCP 只能经过 ws 即 Websocket 连接。因此若是服务器是TCP直连,客户端是确定连不上的,会报 Error in connection establishment 的错误。因此客户端协议只能是ws,wss,wxs(微信)小程序
(3) WebSocket 是一种在单个 TCP 链接上进行全双工通信的协议。做为一种通讯协议,其使用 ws(非加密)、wss(SSL 加密) 做为协议标识。MQTT.js 客户端支持多种协议,链接地址需指明协议类型;微信小程序
(4) ws: 未加密的 WebSocket 链接,通常使用8083端口。wss: 加密的 WebSocket 链接,通常使用8084端口。mqtt: 未加密的 TCP 链接,通常使用1883端口。mqtts: 加密 TCP 链接。浏览器
贴一下代码:服务器
import $mqtt from './mqtt.min.js';
const mqttOptions = { keepalive: 30, clean: false, connectTimeout: 5000, // Timeout clientId: uni.getStorageSync('clientId'), // username: 'test', // password: 'test', } const connectUrl = `${mqttHost}:${mqttPort}/mqtt`; // #ifdef H5 var client = $mqtt.connect('wss://' + connectUrl, mqttOptions); // #endif // #ifdef MP-WEIXIN||APP-PLUS var client = $mqtt.connect('wxs://' + connectUrl, mqttOptions); // #endif client.on('connect', () => { console.log('connect')
// 这是为了给本身发条消息,其它无做用 client.subscribe('test', (err) => { if (!err) { client.publish('test', '{}') } }) }); // 自动重连 client.on('reconnect', (msg) => { console.log('reconnect', msg) }); // 错误 client.on('error', () => { console.log('error') }); // 断开 client.on('end', () => { console.log('end') }); // 掉线 client.on('offline', (msg) => { console.log('offline',msg) }); // 收到消息 client.on('message', (topic, message) => { // 把arrayBuffer转成字符串 let encodedString = String.fromCharCode.apply(null, new Uint8Array(message));// 全局发送消息 uni.$emit('sendTopicMsg',encodedString);
console.log(encodedString) }) // 全局监听是否有关闭mqtt的消息的事件 uni.$on('closeMqtt',() => { client.end(true); // 主动断开链接 })
说明:
(1) 配置项里的 keepAlive 指的是心跳时间。以秒为单位。定义服务端从客户端接收到消息的最大间隔时间。能够设置为0,表示客户端一直不断开,除非主动断开。
(2) clean 设置为false,是为了让客户端掉线的时候,服务器必须在客户端断开以后继续存储/保持客户端的订阅状态。即当为true的时候,若是掉线了,服务端会清理连接状态的数据和内容。当为false的时候,服务端会保存消息发送期间,连接断开致使发送失败的消息。这样连上的时候就会自动推送到订阅的客户端。
(3) 若是链接须要验证用户名和密码,则须要加上username和password字段。
(4) 微信小程序使用的协议,若是不是加密的,则是 wss,若是是加密的,就是 wxs。web端,通常不加密就是 wx,加密就是wss。
(5) 前端收到的消息是 arrayBuffer 格式的,须要转成字符串格式,若是带有中文,可能转成字符串会乱码。可使用 let decodeString = decodeURIComponent(escape((encodedString))) 来避免中文乱码。或者是网上经过移位转成中文的方法来解决。
(6) clientId 是使用 Math.random().toString(36).substr(3,自定义长度) 来生成自定义长度的的惟一id。
应该是免费的测试MQTT消息的连接: o(∩_∩)o
协议 | 地址 | 端口 | 路径 | 证书 |
mqtt | broker.hivemq.com | 8000 | 无 | 无 |
mqtt | broker.emqx.io | 1883 | 无 | 无 |
ws | test.mosquitto.org | 8080 | /mqtt | 无 |
wss | test.mosquitto.org | 8081 | /mqtt | CA signed server |
(1) CA signed server 这个直接在MQTTX测试工具里面 选择 SSL/TLS 勾选为true时便可选择。
(2) 测试的时候,先填好内容,而后连接上的时候,再添加一个订阅,Topic就填一会你须要发送消息的Topic,这样当你模拟服务器发送消息的时候,MQTTX里面也会收到你刚才发送的内容,这样就是连通了。
开发过程当中遇到的问题:
(1) 若是出现 failed: Connection closed before receiving a handshake response 这个错误。说明 服务端的 mqtt 协议和客户端的协议不同,就好比 python用的是基于 tcp 的 mqtt ,js是基于websocket 的 mqtt ,都不能达成握手的操做。出现这个的问题应该是:服务端使用了 1883 这个端口,而客户端也是用这个端口,就致使这个问题。正确的应该是:客户端(js)应该使用 8083 端口(未加密)。
(2) 最初我设置心跳时间是3秒,在微信开发者工具,或者H5端的时候,是没有问题的。可是在小程序真机调试里,当小程序切换到后台,差很少5s就会自动断开,而后一直重连,直到切换回小程序,重连成功。并且有时候还会连续断开和重连。自动断网这个缘由,小程序官网作了说明的:超过5s断网说明 在第二条 网络请求 - 使用限制里面就说明了,小程序的机制,限制了切换到后台以后网络的处理。因此把心跳时间改成30s,让 mqtt 30秒以后再自动重连。可是这样只是为了让体验稍微好一点,不会出现切换出去5s就断开连接,再切回来一直提示重连的问题。不过能够把心跳时间改成0,表示一直链接不断开。
总结:
(1)以上对mqtt的了解也只是只知其一;不知其二,还没弄明白这里的心跳时间,和 TCP/IP 的心跳机制是否是同样的。超过心跳时间,能不能让客户端不掉线,或者有没有更好的解决离线的办法。
(2)并且还有不少特性都没用到,好比will遗愿标志,专门用来处理客户端断开链接的配置项。
(3)因为这个项目都是用的Qos0的消息,都不知道与Qos1,Qos2的区别是什么。
先暂时记录到这里,后面弄懂了再补充。