使⽤WebSocket连接MQTT服务器
近年来随着 Web 前端的快速发展,浏览器新特性层出不穷,越来越多的应⽤可以在浏览器端通过浏览器渲染引擎实现,Web 应⽤的即时通信⽅式 WebSocket 也因此得到了⼴泛的应⽤。
WebSocket 是⼀种在单个 TCP 连接上进⾏全双⼯通讯的协议。WebSocket 通信协议于2011年被 IETF 定为标准 RFC 6455,并由 RFC 7936 补充规范。WebSocket API 也被 W3C 定为标准。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成⼀次握⼿,两者之间就直接可以创建持久性的连接,并进⾏双向数据传输。
详细约定了 MQTT 在 WebSocket [RFC6455] 连接上传输需要满⾜的条件,协议内容不在此详细赘述。
两款客户端⽐较
Paho.mqtt.js
是 Eclipse 的⼀个 MQTT 客户端项⽬,Paho JavaScript Client 是其中⼀个基于浏览器的库,它使⽤ WebSockets 连接到 MQTT 服务器。相较于另⼀个 JavaScript 连接库来说,其功能较少,不推荐使⽤。
MQTT.js
是⼀个完全开源的 MQTT 协议的客户端库,使⽤ JavaScript 编写,可⽤于 Node.js 和浏览器。在 Node.js 端可以通过全局安装使⽤命令⾏连接,同时⽀持 MQTT/TCP、MQTT/TLS、MQTT/WebSocket 连接;值得⼀提的是 MQTT.js 还对⼩程序有较好的⽀持。
本⽂将使⽤ MQTT.js 库进⾏ WebSocket 的连接讲解。
安装 MQTT.js
如果读者机器上装有 Node.js 运⾏环境,可直接使⽤ npm 命令安装 MQTT.js。
在当前⽬录安装
npm install mqtt --save
CDN 引⽤
或免安装直接使⽤ CDN 地址
<script src="unpkg/mqtt/dist/mqtt.min.js"></script>
<script>
// 将在全局初始化⼀个 mqtt 变量
console.log(mqtt)
</script>
连接⾄ MQTT 服务器
本⽂将使⽤ EMQ X 提供的,该服务基于 EMQ X 的创建。服务器接⼊信息如下:
Broker: qx.io
TCP Port: 1883
Websocket Port: 8083
EMQ X 使⽤ 8083 端⼝⽤于普通连接,8084 ⽤于 SSL 上的 WebSocket 连接。
为了简单起见,让我们将订阅者和发布者放在同⼀个⽂件中:
const clientId = 'mqttjs_' + Math.random().toString(16).substr(2, 8)
const host = 'ws://qx.io:8083/mqtt'
const options = {
keepalive: 60,前端websocket怎么用
clientId: clientId,
protocolId: 'MQTT',
protocolVersion: 4,
clean: true,
reconnectPeriod: 1000,
connectTimeout: 30 * 1000,
will: {
topic: 'WillMsg',
payload: 'Connection Closed abnormally..!',
qos: 0,
retain: false
},
}
console.log('Connecting mqtt client')
const client = t(host, options)
<('error', (err) => {
console.log('Connection error: ', err)
})
<('reconnect', () => {
console.log('')
})
连接地址
上⽂⽰范的连接地址可以拆分为:ws: // broker . emqx.io : 8083/mqtt
即协议 // 主机名 . 域名 : 端⼝ / 路径
初学者容易出现以下⼏个错误:
连接地址没有指明协议:WebSocket 作为⼀种通信协议,其使⽤ws (⾮加密)、wss (SSL 加密) 作为协议标识。MQTT.js 客户端⽀持多种协议,连接地址需指明协议类型;
连接地址没有指明端⼝:MQTT 并未对 WebSocket 接⼊端⼝做出规定,EMQ X 上默认使⽤80838084分别作为⾮加密连接、加密连接端⼝。⽽ WebSocket 协议默认端⼝同 HTTP 保持⼀致 (80/443),不填
写端⼝则表明使⽤ WebSocket 的默认端⼝连接;⽽使⽤标准MQTT 连接时则⽆需指定端⼝,如 MQTT.js 在 Node.js 端可以使⽤mqtt://localhost连接⾄标准 MQTT 1883 端⼝,当连接地址是mqtts://localhost则连接到 8884 端⼝;
连接地址⽆路径:MQTT-WebSoket 统⼀使⽤/path作为连接路径,连接时需指明,在 EMQ X 上使⽤的路径为/mqtt;
协议与端⼝不符:使⽤了wss连接却连接到8083端⼝;
在 HTTPS 下使⽤⾮加密的 WebSocket 连接: Google 等机构在推进 HTTPS 的同时也通过浏览器约束进⾏了安全限定,即 HTTPS 连接下浏览器会⾃动禁⽌使⽤⾮加密的ws协议发起连接请求;
证书与连接地址不符:篇幅较长,详见下⽂ EMQ 启⽤ SSL/TLS 加密连接。
连接选项
keepalive:⼼跳时间,默认 60秒,设置 0 为禁⽤;
clientId:客户端 ID ,默认通过'mqttjs_' + Math.random().toString(16).substr(2, 8)随机⽣成;
username:连接⽤户名(可选);
password:连接密码(可选);
clean:true,设置为 false 以在离线时接收 QoS 1 和 2 消息;
reconnectPeriod:默认 1000 毫秒,两次重新连接之间的间隔,客户端 ID 重复、认证失败等客户端会重新连接;
connectTimeout:默认 30 * 1000毫秒,收到 CONNACK 之前等待的时间,即连接超时时间;
will:遗嘱消息,当客户端严重断开连接时,Broker 将⾃动发送的消息。⼀般格式为:
topic:要发布的主题
payload:要发布的消息
qos:QoS
retain:保留标志
订阅/取消订阅
连接成功之后才能订阅,且订阅的主题必须符合 MQTT 订阅主题规则;
注意 JavaScript 的异步⾮阻塞特性,只有在 connect 事件后才能确保客户端已成功连接,或通过ted判断是否连接成功:
<('connect', () => {
console.log('Client connected:' + clientId)
// Subscribe
client.subscribe('testtopic', { qos: 0 })
})
// Unsubscribe
client.unubscribe('testtopic', () => {
console.log('Unsubscribed')
})
发布/接收消息
发布消息到某主题,发布的主题必须符合 MQTT 发布主题规则,否则将断开连接。发布之前⽆需订阅该主题,但要确保客户端已成功连接:
// Publish
client.publish('testtopic', 'ws !', { qos: 0, retain: false })
// Received
<('message', (topic, message, packet) => {
console.log('Received Message: ' + String() + '\nOn topic: ' + topic)
})
⼩程序
MQTT.js 库对⼩程序特殊处理,使⽤wxs协议标识符。注意⼩程序开发规范中要求必须使⽤加密连接,连接地址应类似为
wxs://qx.io:8084/mqtt。
EMQ X 启⽤ SSL/TLS 加密连接
EMQ 内置⾃签名证书,默认已经启动了加密的 WebSocket 连接,但⼤部分浏览器会报证书⽆效错误如
net::ERR_CERT_COMMON_NAME_INVALID (Chrome、360 等 webkit 内核浏览器在开发者模式下, Console 选项卡可以查看⼤部分连接错误)。导致该错误的原因是浏览器⽆法验证⾃签名证书的有效性,读者需从证书颁发机构购买可信任证书,并参考该篇⽂章中的相应部分进⾏配置操作:。
这⾥就总结启⽤ SSL/TLS 证书需要具备的条件是:
将域名绑定到 MQTT 服务器公⽹地址:CA 机构签发的证书签名是针对域名的;
申请证书:向 CA 机构申请所⽤域名的证书,注意选择⼀个可靠的 CA 机构且证书要区分泛域名与主机名;
使⽤加密连接的时候选择wss协议,并使⽤域名连接:绑定域名-证书之后,必须使⽤域名⽽⾮ IP 地址进⾏连接,这样浏览器才会根据域名去校验证书以在通过校验后建⽴连接。
EMQ X 配置
打开f配置⽂件,修改以下配置:
# wss 监听地址
al = 8084
# 修改密钥⽂件地址
al.keyfile = etc/certs/cert.key
# 修改证书⽂件地址
al.certfile = etc/certs/cert.pem
完成后重启 EMQ X 即可。
可以使⽤你的证书与密钥⽂件直接替换到 etc/certs/ 下。
在 Nginx 上配置反向代理与证书
使⽤ Nginx 来反向代理并加密 WebSocket 可以减轻 EMQ X 服务器计算压⼒,同时实现域名复⽤,同时通过 Nginx 的负载均衡可以分配多个后端服务实体。
# 建议 WebSocket 也绑定到 443 端⼝
listen 443, 8084;
server_name example;
ssl on;
ssl_certificate /; # 证书路径
ssl_certificate_key /etc/cert.key; # 密钥路径
# upstream 服务器列表
upstream emq_server {
server 10.10.1.1:8883 weight=1;
server 10.10.1.2:8883 weight=1;
server 10.10.1.3:8883 weight=1;
}
# 普通⽹站应⽤
location / {
root www;
index index.html;
}
# 反向代理到 EMQ X ⾮加密 WebSocket
location / {
proxy_redirect off;
# upstream
proxy_pass emq_server;
proxy_set_header Host $host;
# 反向代理保留客户端地址
proxy_set_header X-Real_IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr:$remote_port; # WebSocket 额外请求头
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection “upgrade”;
}
其它资源
版权声明:本⽂为原创,转载请注明出处。1.
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论