干货 | MQTT协议例析

点击上方“中兴开发者社区”,关注我们

每天读一篇一线开发者原创好文

干货 | MQTT协议例析

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是一套ISO标准的基于发布/订阅机制的消息协议,用于在TCP网络中传输大规模物联网设备数据,是5G通讯的重要服务对象,值得我们花时间去了解学习。IBM于1999年提出MQTT,于2013年将MQTT3.1版本提交给OASIS(Organization for the Advancement of Structured Information Standards )标准化,目前主流的稳定版本为MQTT 3.1.1。MQTT官网为http://mqtt.org/。

干货 | MQTT协议例析

本文采用简单的Node.js程序搭建MQTT基础环境,介绍MQTT的典型应用场景,以供感兴趣的读者参考和理解。以如下序列图为例,在MQTT中可能存在三种类型的网元或终端:

  • CLIENT1和CLIENT2为用于发布(Publish)数据的客户端(通常是物联网终端设备),即“发布者”。

  • CLIENT3和CLIENT4为用于订阅(Subscribe)接收数据的客户端或服务器(也可能是物联网终端设备),即“订阅者”。

  • BROKER用于中转数据,各种IoT云服务平台通常均支持作为此角色,即“代理”。

干货 | MQTT协议例析

  • 方式1:只启动MQTT服务,默认监听1883/TCP端口

  1. 命令:mosca -v

  2. 输出:{"pid":8282,"hostname":"<主机名>","name":"mosca","level":30,"time":1518403379005,"msg":"server started","mqtt":1883,"v":1}

  • 方式2:只启动MQTTS服务(MQTTS,即MQTT over SSL/TLS),默认监听8883/TCP端口

  1. 命令:mosca ---key ../cert/server_key_no_password.pem --cert ../cert/server.pem

  2. 输出:{"pid":8314,"hostname":"<主机名>","name":"mosca","level":30,"time":1518403384861,"msg":"server started","mqtts":8883,"v":1}

  • 方式3:同时启动MQTT和MQTTS服务,默认监听1883/TCP端口和8883/TCP端口

  1. 命令:mosca ---key ../cert/server_key_no_password.pem --cert ../cert/server.pem --non-secure

  2. 输出:{"pid":8333,"hostname":"<主机名>","name":"mosca","level":30,"time":1518403387585,"msg":"server started","mqtt":1883,"mqtts":8883,"v":1}

如图2所示,BROKER采用mosca方式3启动,同时支持MQTT和MQTTS服务。


第二步,编写CLIENT3(MQTT)、CLIENT4(MQTTS)程序以连入BROKER。CLIENT3连入MQTT端口1883,并订阅“ZTE/test/sk/1”主题。CLIENT4连入MQTTS端口8883,订阅同样的“ZTE/test/sk/1”主题,如果该主题收到任何别人发布的消息,则CLIENT3、CLIENT4将同时打印出该消息的内容。

CLIENT3源代码:

  1. var mqtt = require('mqtt');

  2. var client = mqtt.connect({ port: 1883, host: '<BROKER地址>', keepalive: 10000});

  3. client.on('connect', function () {

  4.   console.log('CLIENT3: CONNECTED');

  5. });

  6. client.subscribe('ZTE/test/sk/1');

  7. client.on('message', function (topic, message) {

  8.   console.log('CLIENT3:', message.toString());

  9. });

CLIENT4源代码:

  1. var mqtt = require('mqtt');

  2. var fs = require('fs');

  3. var path = require('path');

  4. var TRUSTED_CA_LIST = fs.readFileSync(path.join(__dirname, 'ca.pem'));

  5. var PORT = 8883;

  6. var HOST = '<BROKER地址>';

  7. var options = {

  8.   port: PORT,

  9.   host: HOST,

  10.   rejectUnauthorized: true,

  11.   ca: TRUSTED_CA_LIST,

  12.   protocol: 'ssl'

  13. };

  14. var client = mqtt.connect(options);

  15. client.on('connect', function () {

  16.   console.log('CLIENT4: CONNECTED');

  17. });

  18. client.subscribe('ZTE/test/sk/1');

  19. client.on('message', function (topic, message) {

  20.   console.log('CLIENT4:', message.toString());

  21. });

第三步,编写CLIENT1(MQTT)、CLIENT2(MQTTS)程序以连入BROKER。CLIENT1连入MQTT端口1883,并向“ZTE/test/sk/1”主题发布消息,消息内容为“CLIENT1 say:”+当前时间。CLIENT2连入MQTTS端口8883,同样也向该主题“ZTE/test/sk/1”发布消息,消息内容为“CLIENT2 say:”+当前时间。

CLIENT1源代码:

  1. var mqtt = require('mqtt');

  2. var client = mqtt.connect({ port: 1883, host: '<BROKER地址>', keepalive: 10000});

  3. client.on('connect', function () {

  4.   console.log('CLIENT1: CONNECTED');

  5. });

  6. client.publish('ZTE/test/sk/1', 'CLIENT1 say: Current time is: ' + new Date());

  7. client.end();

CLIENT2源代码:

  1. var mqtt = require('mqtt');

  2. var fs = require('fs');

  3. var path = require('path');

  4. var TRUSTED_CA_LIST = fs.readFileSync(path.join(__dirname, 'ca.pem'));

  5. var PORT = 8883;

  6. var HOST = '<BROKER地址>';

  7. var options = {

  8.   port: PORT,

  9.   host: HOST,

  10.   rejectUnauthorized: true,

  11.   ca: TRUSTED_CA_LIST,

  12.   protocol: 'ssl'

  13. };

  14. var client = mqtt.connect(options);

  15. client.on('connect', function () {

  16.   console.log('CLIENT2: CONNECTED');

  17. });

  18. client.publish('ZTE/test/sk/1', 'CLIENT2 say: Current time is: ' + new Date());

  19. client.end();

第四步,运行CLIENT3、CLIENT4,连入BROKER,并订阅该主题,以等待该主题的任何消息。

运行CLIENT3:

  1. node 3_mqtt_sub.js

  2. CLIENT3: CONNECTED

运行CLIENT4:

  1. node 4_mqtts_sub.js

  2. CLIENT4: CONNECTED

第五步,运行CLIENT1、CLIENT2,连入BROKER,向该主题发布消息。

运行CLIENT1:

  1. node 1_mqtt_pub.js

  2. CLIENT1: CONNECTED

运行CLIENT2:

  1. node 2_mqtts_pub.js

  2. CLIENT2: CONNECTED

第六步,这时即可观察到CLIENT3、CLIENT4立即打印出相应的消息。

CLIENT3打印:

  1. CLIENT3: CLIENT1 say: Current time is: Mon Feb 12 2018 11:21:57 GMT+0800 (中国标准时间)

  2. CLIENT3: CLIENT2 say: Current time is: Mon Feb 12 2018 11:22:27 GMT+0800 (中国标准时间)

CLIENT4打印:

  1. CLIENT4: CLIENT1 say: Current time is: Mon Feb 12 2018 11:21:57 GMT+0800 (中国标准时间)

  2. CLIENT4: CLIENT2 say: Current time is: Mon Feb 12 2018 11:22:27 GMT+0800 (中国标准时间)

本文通过描述MQTT/MQTTS简单源码例程及BROKER部署,介绍了MQTT的典型应用场景,为读者提供了轻松的入门参考。MQTT是物联网大规模M2M(Machine to Machine)应用的重要协议,是5G通讯的重要服务对象,值得我们进一步深入学习研究。


参考资料:

  1. http://mqtt.org/

  2. https://github.com/mqttjs

  3. https://www.npmjs.com/package/mqtt

  4. https://github.com/mcollina/mosca

  5. http://www.mosca.io/

干货 | MQTT协议例析