内容简介:MQTT(消息队列遥测传输) 是基于 TCP/IP 协议栈而构建的支持在各方之间异步通信的消息协议。MQTT在空间和时间上将消息发送者与接收者分离,因此可以在不可靠的网络环境中进行扩展。虽然叫做消息队列遥测传输,但它与消息队列毫无关系,而是使用了发布和订阅(Pub/Sub)的模型。MQTT 是一种轻量级的、灵活的网络协议,致力于为 IoT 开发人员实现适当的平衡:MQTT Client 库在很多语言中都有实现,包括 Embedded C、C、Java、JavaScript、Python、C++、C#、Go
MQTT(消息队列遥测传输) 是基于 TCP/IP 协议栈而构建的支持在各方之间异步通信的消息协议。MQTT在空间和时间上将消息发送者与接收者分离,因此可以在不可靠的网络环境中进行扩展。虽然叫做消息队列遥测传输,但它与消息队列毫无关系,而是使用了发布和订阅(Pub/Sub)的模型。
MQTT 是一种轻量级的、灵活的网络协议,致力于为 IoT 开发人员实现适当的平衡:
- 这个轻量级协议可在严重受限的设备硬件和高延迟/带宽有限的网络上实现。
- 它的灵活性使得为 IoT 设备和服务的多样化应用场景提供支持成为可能。
1.2 MQTT Client库
MQTT Client 库在很多语言中都有实现,包括 Embedded C、C、 Java 、JavaScript、 Python 、C++、C#、 Go 、iOS、Android等。Eclipse Paho的MQTT库下载地址: www.eclipse.org/paho/downlo…
下面开发实践基于Nodejs版mqtt,获取地址 www.npmjs.com/package/mqt…
1.3 MQTT报文
1.3.1 固定报头Fixed header
Bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
byte 1 |
MQTT控制报文的类型 |
用于指定控制报文类型的标志位 |
||||||
byte 2,3,4,5 |
剩余长度,最大4个字节 |
控制报文类型
名字 | 值 | 报文流动方向 | 描述 |
---|---|---|---|
Reserved | 0 | 禁止 | 保留 |
CONNECT | 1 | Client -> Broker | device连接IoT平台 |
CONNACK | 2 | Broker -> Client | IoT平台确认连接结果 |
PUBLISH | 3 | 双向 | 发布消息 |
PUBACK | 4 | 双向 | QoS=1消息发布收到确认 |
|
|
|
|
|
|
|
|
|
|
|
|
SUBSCRIBE | 8 | Client -> Broker | device订阅IoT平台Topic |
SUBACK | 9 | Broker -> Client | IoT平台确认订阅结果 |
UNSUBSCRIBE | 10 | Client -> Broker | device取消订阅IoT平台Topic |
UNSUBACK | 11 | Broker -> Client | IoT平台确认取消订阅结果 |
PINGREQ | 12 | Client -> Broker | device发送心跳请求到IoT平台 |
PINGRESP | 13 | Broker -> Client | IoT平台响应device心跳 |
DISCONNECT | 14 | Client -> Broker | device断开IoT平台连接 |
Reserved | 15 | 禁止 | 保留 |
控制报文类型标志位
控制报文 | 固定报头标志 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
---|---|---|---|---|---|
PUBLISH | MQTT 3.1.1使用 | DUP | QoS | QoS | RETAIN |
剩余长度
字节数 | 最小值 | 最大值 |
---|---|---|
1 | 0 (0x00) | 127 (0x7F) |
2 | 128 (0x80, 0x01) | 16 383 (0xFF, 0x7F) |
3 | 16 384 (0x80, 0x80, 0x01) | 2 097 151 (0xFF, 0xFF, 0x7F) |
4 | 2 097 152 (0x80, 0x80, 0x80, 0x01) | 268 435 455 (0xFF, 0xFF, 0xFF, 0x7F) |
注:阿里云IoT的单个payload最大256K
1.3.2 可变报头Variable header
某些MQTT控制报文包含一个可变报头部分。它在固定报头和负载之间。可变报头的内容根据报文类型的不同而不同。可变报头的报文标识符(Packet Identifier)字段存在于在多个类型的报文里。
报文标识符字节 Packet Identifier bytes
Bit | 7 - 0 |
---|---|
byte 1 | 报文标识符 MSB |
byte 2 | 报文标识符 LSB |
控制报文 | 报文标识符 |
---|---|
PUBLISH | 需要(如果QoS =1,2) |
PUBACK | 需要 |
PUBREC | 需要 |
PUBREL | 需要 |
PUBCOMP | 需要 |
SUBSCRIBE | 需要 |
SUBACK | 需要 |
UNSUBSCRIBE | 需要 |
UNSUBACK | 需要 |
1.3.3 有效载荷Payload
以下MQTT控制报文在报文的最后部分包含一个有效载荷。对于PUBLISH来说有效载荷就是业务消息。
控制报文 | 有效载荷 |
---|---|
CONNECT | 需要 |
PUBLISH | 可选 |
SUBSCRIBE | 需要 |
SUBACK | 需要 |
UNSUBSCRIBE | 需要 |
2.与阿里云IoT平台建立连接
2.1 CONNECT
阿里云IoT物联网平台的MQTT协议不支持will消息,CONNECT 消息内容参数如下:
参数 |
说明 |
cleanSession |
此标志指定连接是否是持久性的。 0为持久会话,QoS=1消息不会丢失; 1为非持久会话,清理离线消息。 |
clientId |
客户端标识符 |
username |
代理的身份验证和授权凭证。 |
password |
代理的身份验证和授权凭证。 |
keepAlive |
心跳时间, IoT平台约定心跳范围 30s~1200s |
其中clientId,username,password由设备三元组(productKey,deviceName,deviceSecret)按照规则生成,具体规则如下:
clientId |
id +"|securemode=3,signmethod=hmacsha1,timestamp="+timestamp+"|" |
id :表示客户端ID,64字符内 。其中 || 内为扩展参数。 securemode:安全模式;2为TLS加密,3为非加密 signmethod:签名算法类型。 timestamp:当前时间毫秒值。 |
username |
deviceName+"&"+productKey |
|
password |
sign_hmac(deviceSecret,content) |
sign_hmac为clientId中的signmethod算法类型 content为如下拼接字符串: " clientId ${ id } deviceName ${deviceName} productKey ${productKey} timestamp ${timestamp}" |
官方文档: help.aliyun.com/document_de…
设备端代码示例(Nodejs版) client.js
/** "dependencies": { "mqtt": "2.18.8" } */ const crypto = require('crypto'); const mqtt = require('mqtt'); //设备身份三元组+区域 const deviceConfig = { productKey: "替换", deviceName: "替换", deviceSecret: "替换", regionId: "cn-shanghai" }; //根据三元组生成mqtt连接参数 const options = initMqttOptions(deviceConfig); const url = `tcp://${deviceConfig.productKey}.iot-as-mqtt.${deviceConfig.regionId}.aliyuncs.com:1883`; //2.建立连接 const client = mqtt.connect(url, options); client.on('packetsend', function (packet){ console.log('send '+packet.cmd+' packet =>',packet) }) client.on('packetreceive', function (packet){ console.log('receive '+packet.cmd+' packet =>',packet) }) //IoT平台mqtt连接参数初始化 function initMqttOptions(deviceConfig) { const params = { productKey: deviceConfig.productKey, deviceName: deviceConfig.deviceName, timestamp: Date.now(), clientId: Math.random().toString(36).substr(2), } //CONNECT参数 const options = { keepalive: 60, //60s clean: false, //cleanSession保持持久会话 protocolVersion: 4 //MQTT v3.1.1 } //1.生成clientId,username,password options.password = signHmacSha1(params, deviceConfig.deviceSecret); options.clientId = `${params.clientId}|securemode=3,signmethod=hmacsha1,timestamp=${params.timestamp}|`; options.username = `${params.deviceName}&${params.productKey}`; return options; } /* 生成基于HmacSha1的password 参考文档:https://help.aliyun.com/document_detail/73742.html?#h2-url-1 */ function signHmacSha1(params, deviceSecret) { let keys = Object.keys(params).sort(); // 按字典序排序 keys = keys.sort(); const list = []; keys.map((key) => { list.push(`${key}${params[key]}`); }); const contentStr = list.join(''); return crypto.createHmac('sha1', deviceSecret) .update(contentStr) .digest('hex'); } 复制代码
2.2 CONNACK
receive connack packet => Packet { cmd: 'connack', retain: false, qos: 0, dup: false, length: 2, topic: null, payload: null, sessionPresent: false, returnCode: 0 } 复制代码
2.4 PINGRESP
send pingreq packet => { cmd: 'pingreq' } 复制代码
2.5 PINGRESP
receive pingresp packet => Packet { cmd: 'pingresp', retain: false, qos: 0, dup: false, length: 0, topic: null, payload: null } 复制代码
2.6 DISCONNECT
3. 发布数据
3.1 PUBLISH
//3.属性数据上报 const topic = `/sys/${deviceConfig.productKey}/${deviceConfig.deviceName}/thing/event/property/post`; setInterval(function() { //发布数据到topic client.publish(topic, getPostData(),{qos:1}); }, 5 * 1000); function getPostData() { const payloadJson = { id: Date.now(), params: { temperature: Math.floor((Math.random() * 20) + 10), humidity: Math.floor((Math.random() * 20) + 60) }, method: "thing.event.property.post" } console.log("===postData\n topic=" + topic) console.log(payloadJson) return JSON.stringify(payloadJson); } 复制代码
send publish packet => { cmd: 'publish', topic: '/sys/a1hQSwFledE/eud1jXfEgCsAiP2eId9Q/thing/event/property/post', payload: '{"id":1543896481106,"params":{"temperature":23,"humidity":73},"method":"thing.event.property.post"}', qos: 1, retain: false, messageId: 38850, dup: false } 复制代码
3.2 PUBACK
receive puback packet => Packet { cmd: 'puback', retain: false, qos: 0, dup: false, length: 2, topic: null, payload: null, messageId: 38850 } 复制代码
4. 接收数据
4.1 SUBSCRIBE
//4.订阅主题,接收指令 const subTopic = `/${deviceConfig.productKey}/${deviceConfig.deviceName}/control`; client.subscribe(subTopic) client.on('message', function(topic, message) { console.log("topic " + topic) console.log("message " + message) }) 复制代码
SUBSCRIBE消息体
send subscribe packet => { cmd: 'subscribe', subscriptions: [ { topic: '/a1hQSwFledE/eud1jXfEgCsAiP2eId9Q/control', qos: 0 } ], qos: 1, retain: false, dup: false, messageId: 38851 } 复制代码
4.2 SUBACK
SUBACK消息体
receive suback packet => Packet { cmd: 'suback', retain: false, qos: 0, dup: false, length: 3, topic: null, payload: null, granted: [ 128 ], messageId: 38851 } 复制代码
4.3 UNSUBSCRIBE
send unsubscribe packet => { cmd: 'unsubscribe', qos: 1, messageId: 34323, unsubscriptions: [ '/a1hQSwFledE/eud1jXfEgCsAiP2eId9Q/control' ] } 复制代码
4.4 UNSUBACK
receive unsuback packet => Packet { cmd: 'unsuback', retain: false, qos: 0, dup: false, length: 2, topic: null, payload: null, messageId: 34323 } 复制代码
5. 服务质量QoS
服务质量 Quality of Service |
描述 |
阿里云IoT |
QoS=0 |
最多一次的传输,可能会收不到消息 |
支持 |
QoS=1 |
至少一次的传输,一定会收到消息,可能重复 |
支持 |
QoS=2 |
有且仅有一次的传输 |
不支持 |
6. 设备掉线重连
设备与阿里云IoT的订阅关系在云端保持,除非设备主动unsubscribe,否则订阅关系不清理。设备重连后,依然保持之前的订阅关系,不需要重复订阅。
7. 传输层安全TLS 1.2
设备和IoT平台之间的链路可以通过TLS v1.2加密。 如果使用TLS加密,需要下载根证书。 CONNECT参数中clientId的 securemode=2
IoT物联网技术
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- HBase平台|58同城HBase平台建设实践
- 以太坊:区块链平台开发人员希望工作的平台
- 共享定制云平台 AWCP 平台 1.6 发布,集成 solr 引擎
- 共享定制云平台 AWCP 平台 1.6 发布,集成 solr 引擎
- 开源 AI 模型开发平台「天枢平台」已在 Gitee 开源
- asp.net快速开发平台,给开发平台提提速
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。