最近遇到的MQTT相关问题及解决路径。

安装mqtt 库 npm install mqtt
var mqtt = require(‘mqtt’);
var mqClient = mqtt.connect(mqOption);

Mows – MQTT.js over WebSockets
npm install mows –save
Tunnel MQTT through HTML5 websockets using node.js Streams, thanks to websocket-stream.
Mows is based on MQTT.js and it offers the same high-level API.

import ‘@/libs/mqttws31’
created() {
var options = {
timeout: 3,
useSSL: false,
userName: “userForBroker”,
password: “passForBroker”,
cleanSession: true,
onSuccess: this.onConnect,
onFailure: function (message) {
console.log(message.errorMessage);
}
};
this.client.onConnectionLost = this.onConnectionLost;
this.client.onMessageArrived = this.onMessageArrived;
this.client.connect(options);
// this.client.disconnect();
},

The other way of using mqtt on Vue:
export default {
name: ‘mqttws’,
data() {
return {
hostname: ‘39.106.63.136’,
port: 443,
clientId: ‘clientId-NX75qTbKES’,
timeout: 5,
keepAlive: 50,
cleanSession: false,
ssl: false,
userName: ‘hj’,
password: ‘123456’,
topic: ‘001/in’,
client:{},
options: {},
msg:’order’,
count:0
}
},
created : function() {
this.client = new Paho.MQTT.Client(‘39.106.63.136’, 443, ‘clientId-NX75qTbKES’);

}
}

For mqtt @npm:
mqtt.Client(streamBuilder, options)
options is the client connection options (see: the connect packet). Defaults:
wsOptions: is the WebSocket connection options. Default is {}. It’s specific for WebSockets. For possible options have a look at: https://github.com/websockets/ws/blob/master/doc/ws.md.

wsOptions:
new WebSocket.Server(options[, callback])
options {Object}
host {String} The hostname where to bind the server.
port {Number} The port where to bind the server.
backlog {Number} The maximum length of the queue of pending connections.
server {http.Server|https.Server} A pre-created Node.js HTTP/S server.
verifyClient {Function} A function which can be used to validate incoming connections. See description below.
handleProtocols {Function} A function which can be used to handle the WebSocket subprotocols. See description below.
path {String} Accept only connections matching this path.
noServer {Boolean} Enable no server mode.
clientTracking {Boolean} Specifies whether or not to track clients.
perMessageDeflate {Boolean|Object} Enable/disable permessage-deflate.
maxPayload {Number} The maximum allowed message size in bytes.

Self-signed certificates
You can pass the following option to the connect function when using self-signed certificates (for testing purposes only):
mqtt.connect(‘mqtts://test.mosquitto.org’, {
rejectUnauthorized: false
});
In case mqtts (mqtt over tls) is required, the options object is passed through to tls.connect().
If you are using a self-signed certificate, pass the rejectUnauthorized: false option. Beware that you are exposing yourself to man in the middle attacks, so it is a configuration that is not recommended for production environments.

tls.connect(options[, callback])
tls.connect(path[, options][, callback])#
Added in: v0.11.3
tls.connect(port[, host][, options][, callback])#
Added in: v0.11.3
https://nodejs.org/api/tls.html#tls_tls_connect_options_callback

const tls = require(‘tls’);
const fs = require(‘fs’);
const options = {
// Necessary only if using the client certificate authentication
key: fs.readFileSync(‘client-key.pem’),
cert: fs.readFileSync(‘client-cert.pem’),

// Necessary only if the server uses the self-signed certificate
ca: [ fs.readFileSync(‘server-cert.pem’) ]
};
const socket = tls.connect(8000, options, () => {
console.log(‘client connected’,
socket.authorized ? ‘authorized’ : ‘unauthorized’);
process.stdin.pipe(socket);
process.stdin.resume();
});

The options object needs to include a ca key that points to the certificate used to sign the brokers certificate. As it looks like your using a self signed certificate this will be the same one used by the broker.
Or you can allow any certificate with the rejectUnauthorized key as mentioned in @notion’s answer. But that makes it impossible to detect if somebody is impersonating your broker

mosquitto.conf:
I have since managed to connect to mosquito using the Paho MQTT client for javascript! I made slight changes to mosquitto.conf:
listener 8880
protocol mqtt

listener 8881
protocol websockets
cafile /home/hi/cert/ca.crt
certfile /home/hi/cert/hi.com.crt
keyfile /home/hi/cert/hi.com.key
tls_version tlsv1

bind_address hi-server
Tells mosquitto to only listen for websocket connections on localhost not any of the public interfaces.

# By default a TLS enabled listener will operate in a similar fashion to a
# https enabled web server, in that the server has a certificate signed by a CA
# and the client will verify that it is a trusted certificate. The overall aim
# is encryption of the network traffic. By setting require_certificate to true,
# the client must provide a valid certificate in order for the network
# connection to proceed. This allows access to the broker to be controlled
# outside of the mechanisms provided by MQTT.
#require_certificate false
# IP address/hostname to bind the default listener to. If not
# given, the default listener will not be bound to a specific
# address and so will be accessible to all network interfaces.
# bind_address ip-address/host name
#bind_address

1539671798: Saving in-memory database to /var/lib/mosquitto/mosquitto.db.
1539671798: Error saving in-memory database, unable to open /var/lib/mosquitto/mosquitto.db.new for writing.

The hivemq demo uses a JS (mqttws31.js) in browser to access the MQTT broker, and thus it won’t support self-signed ssl certificates by default – it depends on the trusted CA certificates installed in your browser.
You need a CA SSL certificate, and configure it in your emq.conf file.
If you just want to have a try with you self-signed certificate (there’s already one configured in the emq.conf), try to install the cert in your browser by accessing ‘https://xxxx:8084/mqtt’, and then select ‘continue’ if any warning about security.

Or get a free personal cert: http://cert.startcom.org/
The thing is that I bought a SSL certificate from Comodo (EsentialSSL Certificate). I have working HTTPS server on my domain,
I can connect via wss:// to my server from Safari (as of version 6.0.2) and from Firefox (as of version 18.0), but can not from Google Chrome. What am I doing wrong?
I set the autoAcceptConnections option to false and it works (in all browsers).

MQTT Mosquitto broker with SSL/TLS transport security
Websocket over SSL: Firefox Browser – security – certificates – (NO: people import….cafile)
– servers – Add Exception (https://TW:9002).
Or
Before we can use the MQTT websockets with TLS/SSL enabled we need to use the browser and visit the following URL:
Input https://TW:9002 in firefox and add an exception, then WSS works.
Could be tested:
http://www.hivemq.com/demos/websocket-client/

if (cafile && cafile != “”) {
useTLS = true;
}
Then wss://TW:9002 works.

STEPS:
1. cnpm install mathjs –save
2. import * as Math from ‘mathjs’

data: {
client: new Paho.MQTT.Client(BrokerIP, 9001, ‘/mqtt’, this.clientID, 10),
},
computed: {
clientID: function() {
return (‘web_’ + parseInt(Math.random() * 100));
}
}
3. cnpm run dev
[Vue warn]: Error in data(): “ReferenceError: clientID is not defined”
4. Changes:
data: {
client: new Paho.MQTT.Client(BrokerIP, 9001, ‘/mqtt’, (‘web_’ + parseInt(Math.random() * 100)), 10),
},
Or
5. Move clientID from computed to methods.
=>Works.

mathjs is not necessary as Math is a global object.
//import * as Math from ‘mathjs’
cnpm uninstall mathjs –save

手动删除mathjs后,运行cnpm run dev出现错误:
Error: Cannot find module ‘define-properties’
添加回mathjs到package.json,运行cnpm install后还是出错。
=>
解决方案1:
使用npm,cnpm总会有奇奇怪怪的错误
(cnpm install)
解决方案2:
新版的npm会自动将包添加到package.json,旧版的就记得每次install新的包都要带–save参数,这样才能在package.json里有记录。
这样也方便别人只能用你的东西,直接npm install就可以完成全部搭建。

mqtt message handler:
onMessageArrived: function(message) {
console.log(“mqtt message:” + message.payloadString);
var topics = message.destinationName;
var msg = JSON.parse(message.payloadString);

if (topics == “/v1/SensorRead”) {
if (msg.SensorID == “Sensor1”) {
this.inforCardData2[1].count = parseInt(msg.Temp);
}
}
},

Mosca是MQTT在Node.js中的一个Broker的开源实现,通俗讲也就是MQTT中的Server实现。同时作者也维护着MQTT.js这一模块,这一模块大家可理解为MQTT的Client实现。
如何实现离线消息功能
这里所说的离线消息是指,当设备离线Mqtt断开了之后,这时候向用户推送的数据,会在用户下次上线的时候推给用户。
这个地方客户端有两个关键点:
客户端cleanSession需要设置为false.则该链接便会认为是持久连接,当链接断开的时候,发送的消息便会进行报错,直到下次链接再次建立,会将这些消息发送给客户端
Qos标志,在Mqtt标准钟,对Qos有3种设置,在这里我们需要将Qos设置为1。
我之前一同事进行过测试,当采用redis,mongodb作为发布订阅模型的话会出现离线消息数据错乱的情况,经过多次测试之后,我发现ZeroMQ,和RabbitMQ这种消息队列的离线数据是完全按照发送的顺序,离线发送。

发送消息客户端:
var mqtt = require(‘mqtt’);
var client = mqtt.connect(‘mqtt://192.168.1.136:8000’);//连接到服务端
var num = 0;
var qtt = {};//定义消息(可以为字符串,对象等)
qtt.aa = ‘发布’;
qtt.bb = ‘消息!’;

setInterval(function() {
//发布主题为Test的消息
client.publish(‘test’,JSON.stringify(qtt),{qos:1,retain:true});//hello mqtt + num++
},1000);

接收消息的客户端;
var mqtt = require(‘mqtt’);
var client2 = mqtt.connect(“mqtt://192.168.1.136:8000”);

client2.subscribe(‘test’,{qos:1});//订阅主题为test的消息

client2.on(‘message’,function(top,message) {
console.log(message.toString());
});

MQTT client on Nodejs:
> cnpm install –save mqtt
发送消息客户端:
var mqtt = require(‘mqtt’);
var client = mqtt.connect(‘mqtt://BROKER_HOST:1883’);//连接到服务端
var num = 0;
var qtt = {};//定义消息(可以为字符串,对象等)
qtt.aa = ‘发布’;
qtt.bb = ‘消息!’;
setInterval(function() {
//发布主题为Test的消息
client.publish(‘test’,JSON.stringify(qtt),{qos:1,retain:true});//hello mqtt + num++
},1000);

接收消息的客户端;
var mqtt = require(‘mqtt’);
var client = mqtt.connect(“mqtt://10.67.68.56:1883”, {username: “usr1”, password: “pwdusr1”});
client.subscribe(‘#’,{qos:1});
client.on(‘connect’,function(conn) {
console.log(“MQTT connected.”);
});
client.on(‘message’,function(top,message) {
console.log(message.toString());
});
1541053717: mosquitto version 1.5 starting
1541053717: Config loaded from /etc/mosquitto/mosquitto.conf.
1541053717: Opening ipv4 listen socket on port 8883.
1541053717: Opening ipv6 listen socket on port 8883.
1541053717: Opening ipv4 listen socket on port 1883.
1541053717: Opening ipv6 listen socket on port 1883.
1541053717: Opening websockets listen socket on port 9001.
1541053717: Opening websockets listen socket on port 9002.

Error: MQTT connected:undefined
this.client.on(‘connect’,function(conn) {
console.log(“MQTT connected:” + this.link);
});
=>
回调函数内部的this并不是父对象。去除this即可。
this.client.on(‘connect’,function(conn) {
console.log(“MQTT connected:” + link);
});
>node ./server/app.js

Auth for MQTT:
https://mosquitto.org/blog/2013/07/authentication-plugins/
There has been some interest in authentication plugins for mosquitto recently. Some examples have appeared:
Authentication based on md5 hashes: mosquitto_auth_plugin_md5
Authentication based on md5 hashed passwords in postgresql: mosquitto_auth_plugin_pg_md5
Authentication and topic ACL with redis and a PBKDF2 hash: mosquitto-redis-auth
I particularly like the redis based plugin for the interesting additions like the “superuser” that is exempt from ACL checks.

https://github.com/jpmens/mosquitto-auth-plug
Authentication plugin for Mosquitto with multiple back-ends (MySQL, Redis, CDB, SQLite3)

The scope of this post is to introduce OAuth 2.0 and explain how it can be used with MQTT. In IoT, there are a lot of different use cases that involve OAuth 2.0.
What is OAuth 2.0 ?
OAuth 2.0 is an authorization framework that allows a client to access a resource that is owned by a resource owner without giving unencrypted credentials to the client.

User name: The user name is the same value for all devices: use-token-auth. This value causes Watson IoT Platform to use the device’s authentication token, which is specified as the password.
Password: The password for each device is the unique authentication token that was generated when the device was registered with Watson IoT Platform.

https://auth0.com/docs/integrations/authenticating-devices-using-mqtt
Authenticating & Authorizing Devices using MQTT with Auth0
mosca is a nodejs based messaging broker that implements other protocols besides MQTT. It offers great extensibility features. It is surprisingly simple to integrate with Auth0.

I connected client with username and password successfully like:
var client = new Paho.MQTT.Client(“domain.com”, Number(port), “myClientId” + new Date().getTime());
client.connect({userName : “username”,password : “123456”,onSuccess:onConnect,onFailure:doFail});
with above code all working fine, problem is how to protect my password because password is open for user when see in view page source, then user can send messages directly to subscribers using below client
http://www.eclipse.org/paho/clients/js/utility/index.html
how can I prevent this?

https://github.com/jpmens/mosquitto-auth-plug/
Any plugin for mosquitto is going to have to be written in something that can be compiled to a native shared library that can be loaded by mosquitto. This would normally mean C or C++
There are hooks in place for the authentication plugin, but none for message storage or anything else so that is unlikely to work without modifying mosquitto directly.
You should examine the code for the auth-plugin and for mosquitto for details.
After a make you should have a shared object called auth-plug.so which you will reference in your mosquitto.conf.
The plugin is configured in Mosquitto’s configuration file (typically mosquitto.conf), and it is loaded into Mosquitto auth the auth_plugin option.
auth_plugin /path/to/auth-plug.so

Mosquitto Go Auth
Mosquitto Go Auth is an authentication and authorization plugin for the Mosquitto MQTT broker.
https://github.com/iegomez/mosquitto-go-auth
auth_opt_password_path /path/to/password_file
auth_opt_acl_path /path/to/acl_file

ACL file =>
user test1
topic write test/topic/1
topic read test/topic/2
user test2
topic read test/topic/+
user test3
topic read test/#
pattern read test/%u
pattern read test/%c


发表评论

电子邮件地址不会被公开。