弄了两天,感觉mqtt中的wss是个大坑,非常不好用,但https网页环境中又必须要用,记录下爬坑过程!
1.需要搭建mqtt服务器,制作证书,搭建nginx,配置wss代理,配置mqtt客户端;
2.mqtt服务器选择mosquitto-1.4.4,搭建过程请参考https://blog.csdn.net/u013332124/article/details/79480639(注意要在linux通过源码编译方式安装,由于默认未开启websockets,需要在config.mk文件中开启,再进行编译);
mosquitto安装后需要先配置,才能启动,有这几点:配置启动用户user,mqtt端口,ws端口。
启动(默认安装位置etc/mosquitto):mosquitto -c mosquitto.conf -v
上图中的1883为mqtt端口,3003为ws端口,8883为mqtts端口(添加ssl证书后),3004为wss端口(添加ssl证书后)。
3.证书制作使用generate-CA.sh,使用方法请参考https://blog.csdn.net/peakguy/article/details/71634842。
证书分为服务器证书和客户端证书:
rnd185.fro.local(默认服务器域名)开头的都为服务器证书,mqtt18501(手动指定)的为客户端证书。
其中需要用到的证书有ca.crt、rnd185.fro.local.key、rnd185.fro.local.crt(mqtt服务器用到);mqtt18501.crt、mqtt18501.key(mqtt客户端用到,nginx代理wss也会用到)。
再次配置mosquitto.conf,如下:
port 1883
listener 8883
cafile /xx/xx/ca.crt
certfile /xx/xx/rnd185.fro.local.crt
keyfile /xx/xx/rnd185.fro.local.key
listener 3003
protocol websockets
listener 3004
protocol websockets
cafile /xx/xx/ca.crt
certfile /xx/xx/rnd185.fro.local.crt
keyfile /xx/xx/rnd185.fro.local.key
4.这时先保证ws通信正常。
ws和wss客户端都使用node的同一套代码(wss只需要修改下var host = 'wss://nginx地址:443/mqtt'),node使用的mqtt版本为2.18.8。
var mqtt = require('mqtt');
var fs = require('fs');
var clientId = 'mqttjs_' + Math.random().toString(16).substr(2, 8)
var host = 'ws://192.168.0.185:3003'
var options = {
keepalive: 60,
clientId: clientId,
protocolId: 'MQTT',
protocolVersion: 4,
clean: true,
reconnectPeriod: 1000,
connectTimeout: 30 * 1000,
will: {
topic: 'WillMsg',
payload: 'Connection Closed abnormally..!',
qos: 0,
retain: false
},
username: 'demo',
password: 'demo',
rejectUnauthorized: false
}
var client = mqtt.connect(host, options)
client.on('error', function (err) {
console.log(err)
client.end()
})
client.on('connect', function () {
console.log('client connected:' + clientId)
})
client.subscribe('topic', { qos: 0 })
client.publish('topic', 'wss secure connection demo...!', { qos: 0, retain: false })
client.on('message', function (topic, message, packet) {
console.log('Received Message:= ' + message.toString() + '\nOn topic:= ' + topic)
})
client.on('close', function () {
console.log(clientId + ' disconnected')
})
脚本执行结果:
服务器日志:
5.如果按照前面的配置,mqtts也是可以的,网上有很多资料,不再细说;这时wss的大坑就来了,在脚本中直接使用wss是有问题的。
测试步骤:
第1步:修改node脚本,var host = 'wss://192.168.0.185:3004';
第2步:直接运行该脚本,客户端会连不上,而服务器将报错,不知道具体原因,有大神知道的可回复我。
客户端连接不上:
服务器报错:
6.使用nginx代码解决wss问题,安装nginx-1.14.0(我的为windows版本,应该跟系统无关),配置nginx.conf。
upstream mqttws {
server 192.168.0.185:3003; #mqtt服务器地址
}
server {
listen 443;
server_name localhost;
ssl on;
ssl_certificate C:\\frotech\\scratch-desktop-bak\\nginx-1.14.0\\ssl\\mqtt18501.crt;
ssl_certificate_key C:\\frotech\\scratch-desktop-bak\\nginx-1.14.0\\ssl\\mqtt18501.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location /mqtt {
proxy_pass http://mqttws;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
7.启动nginx,到nginx安装路径下cmd执行start nginx;修改node客户端脚本(var host = 'wss://192.6.1.74:443/mqtt',其它不用改,192.6.1.74为nginx主机地址,443为端口),运行node客户端脚本,这次可以连接上了。
客户端:
服务器: