请选择 进入手机版 | 继续访问电脑版
 找回密码
 立即注册
搜索

MQTT协议与阿里云IoT物联网平台

本文首发于阿里云 IoT 开发者社区,作者一澄,阿里云 IoT 技术专家。更多精彩内容与活动欢迎移步社区。
1.MQTT协议详情

1.1 MQTT协议

MQTT(消息队列遥测传输) 是基于 TCP/IP 协议栈而构建的支持在各方之间异步通信的消息协议。MQTT在空间和时间上将消息发送者与接收者分离,因而可以在不可靠的网络环境中进行扩展。虽然叫做消息队列遥测传输,但它与消息队列毫无关系,而是使用了发布和订阅(Pub/Sub)的模型。
MQTT 是一种轻量级的、灵活的网络协议,致力于为 IoT 开发人员实现适当的平衡:
    这个轻量级协议可在严重受限的设备硬件和高延迟/带宽有限的网络上实现。 它的灵活性使得为 IoT 设备和服务的多样化应用场景提供支持成为可能。


MQTT协议与阿里云IoT物联网平台-1.jpg

1.2 MQTT Client库

MQTT Client 库在很多语言中都有实现,包括 Embedded C、C、Java、JavaScript、Python、C++、C#、Go、iOS、Android等。Eclipse Paho的MQTT库下载地址:https://www.eclipse.org/paho/downloads.php


MQTT协议与阿里云IoT物联网平台-2.jpg

下面开发实践基于Nodejs版mqtt,获取地址 https://www.npmjs.com/package/mqtt
1.3 MQTT报文



MQTT协议与阿里云IoT物联网平台-3.jpg

1.3.1 固定报头Fixed header

MQTT协议与阿里云IoT物联网平台-4.jpg 控制报文类型
MQTT协议与阿里云IoT物联网平台-5.jpg MQTT协议与阿里云IoT物联网平台-6.jpg 控制报文类型标志位
MQTT协议与阿里云IoT物联网平台-7.jpg 剩余长度
MQTT协议与阿里云IoT物联网平台-8.jpg 注:阿里云IoT的单个payload最大256K
1.3.2 可变报头Variable header

某些MQTT控制报文包含一个可变报头部分。它在固定报头和负载之间。可变报头的内容根据报文类型的不同而不同。可变报头的报文标识符(Packet Identifier)字段存在于在多个类型的报文里。
报文标识符字节 Packet Identifier bytes

MQTT协议与阿里云IoT物联网平台-9.jpg MQTT协议与阿里云IoT物联网平台-10.jpg 1.3.3 有效载荷Payload
以下MQTT控制报文在报文的最后部分包含一个有效载荷。对于PUBLISH来说有效载荷就是业务消息。
MQTT协议与阿里云IoT物联网平台-11.jpg 2.与阿里云IoT平台建立连接



MQTT协议与阿里云IoT物联网平台-12.jpg

2.1 CONNECT

阿里云IoT物联网平台的MQTT协议不支持will消息,CONNECT 消息内容参数如下:
MQTT协议与阿里云IoT物联网平台-13.jpg 其中clientId,username,password由设备三元组(productKey,deviceName,deviceSecret)按照规则生成,具体规则如下:
MQTT协议与阿里云IoT物联网平台-14.jpg 官方文档:https://help.aliyun.com/document_detail/73742.html
设备端代码示例(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



MQTT协议与阿里云IoT物联网平台-15.jpg

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描述阿里云IoTQoS=0最多一次的传输,可能会收不到消息支持QoS=1至少一次的传输,一定会收到消息,可能重复支持QoS=2有且仅有一次的传输不支持


MQTT协议与阿里云IoT物联网平台-16.jpg

6. 设备掉线重连

设备与阿里云IoT的订阅关系在云端保持,除非设备主动unsubscribe,否则订阅关系不清除。设备重连后,依然保持之前的订阅关系,不需要重复订阅。
7. 传输层安全TLS1.2

设备和IoT平台之间的链路可以通过TLS v1.2加密。 假如使用TLS加密,需要下载根证书。 CONNECT参数中clientId的securemode=2
https://help.aliyun.com/document_detail/73742.html   
MQTT协议与阿里云IoT物联网平台-17.jpg 现在开通阿里云物联网平台,可获每日 10 日活设备及每月 100万条免费消息额度。
直达链接
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册