使用阿里物模型深入解释MQTT原理
定义
MQTT(Message Queuing Telemetry Transport)消息队列遥测传输协议是一种轻量级的基于发布/订阅模型的消息传输协议,主要用于物联网(IoT)环境中设备间的通信。它被设计为简单、开放、易于实现,并且可以支持低带宽、高延迟或不可靠的网络环境。
特点
MQTT 的主要特点包括:
- 轻量级:协议本身非常简洁,消息体小,适合在资源受限的设备上使用。
- 发布/订阅模型:消息的发布者(发布者)将消息发送到一个主题(Topic),而订阅者(Subscriber)订阅感兴趣的主题并接收相应的消息。
- 可靠传输:支持消息的可靠传输,确保消息在网络不稳定的情况下也能被正确传递。
- 低功耗:适合在电池供电的设备上使用,因为它可以快速进入低功耗模式。
- 安全性:支持多种安全机制,如TLS/SSL加密传输和用户认证。
- 高扩展
- 协议简单
- 双向通信
工作流程
MQTT 的工作流程:
- 连接:客户端首先与服务器建立连接。
- 订阅:客户端订阅一个或多个主题。
- 发布:客户端或服务器发布消息到一个主题。
- 接收:订阅者接收到订阅主题的消息。
- 断开连接:客户端完成通信后断开与服务器的连接。
- 而在物联网的应用中,MQTT协议消息的具体传输过程,以业务服务器向设备下发消息为例:
- 设备订阅相应的主题(Topic)。
- 服务器发送消息给物联网平台。
- 物联网平台接收消息,根据消息的主题(Topic)确定设备并发送消息。
- 业务服务器收到物联网平台的消息,确认消息已成功发送。
具体内容
1. 协议基础
- 协议版本:主要有两个版本,MQTT 3.1和MQTT 3.1.1。阿里物联网平台还用MQTT5.0。
- 协议端口:默认使用1883端口(非加密)和8883端口(加密)。
- MQTT客户端(Client)和MQTT代理者(Broker):
MQTT客户端(Client):阿里物模型中的客户端(Client)指接入物联网平台的设备。设备和用户的服务器不直接建立连接,而是通过代理者(Broker)进行通信。
MQTT代理者(Broker):阿里物模型中的MQTT代理者(Broker)指阿里云物联网平台。代理者(Broker)是设备和业务服务器消息通信的中介,解耦了设备和业务服务器,实现了设备和业务服务器之间的异步通信。
2. 消息类型
MQTT协议定义了多种消息类型,主要包括:
- CONNECT:客户端向服务器发送连接请求。
- CONNACK:服务器响应客户端的连接请求。
- PUBLISH:发布消息到服务器,服务器再将消息分发给订阅者。
- PUBACK:确认PUBLISH消息已被接收。
- PUBREC:QoS 1消息的接收确认。
- PUBREL:QoS 2消息的发布确认。
- PUBCOMP:QoS 2消息的最终确认。
- SUBSCRIBE:客户端订阅一个或多个主题。
- SUBACK:服务器响应客户端的订阅请求。
- UNSUBSCRIBE:客户端取消订阅一个或多个主题。
- UNSUBACK:服务器响应客户端的取消订阅请求。
- PINGREQ:客户端发送心跳包,检查连接状态。
- PINGRESP:服务器响应心跳包。
- DISCONNECT:客户端或服务器发送断开连接的请求。
3. 消息质量(QoS)(Quality of Service)
MQTT支持三种消息质量等级:
- QoS 0:最多一次传输,消息可能丢失,但不保证送达。
- QoS 1:至少一次传输,消息至少送达一次,可能重复。
- QoS 2:只有一次传输,消息只送达一次,确保送达。
- 在物模型中,QoS=0代表物联网平台只推送一次消息给订阅者。消息最多收到一次,消息不可靠传输,消息可能丢失。传感器数据传输使用Qos=0。
- QoS=1代表订阅者收到消息后必须返回puback给发布者,否则会一直推送消息。消息最少收到一次,消息可靠传输,消息必达。远程控制指令使用Qos=1。
- Qos=2在物联网平台中并不支持。
- 对于MQTT 3.1.1版本协议,如果设备订阅了自己发布消息的Topic,则设备会接收到自己发布的消息。而使用MQTT 5.0版本协议,此场景下,设备在订阅Topic时,可以设置此选项为1,设备将不会接收到自己发布的消息。
- MQTT协议消息的组成部分
- 主题(Topic):使用正斜杠(/)作为分隔符构造字符串,例如/${productKey}/${deviceName}/user/update,订阅该Topic的所有设备都会收到消息。
- 消息内容(Payload):消息的具体内容。
4. 主题(Topic)
MQTT使用主题来组织消息。主题是一个字符串,通常采用层次结构,如“home/livingroom/temperature”。客户端可以订阅一个或多个主题,接收这些主题的消息。
- 在物联网中,有Topic相关、设备接入、连接通信等使用限制, 使用限制。
- 物联网中,有更详细的Topic划分,
基础通信Topic:设备使用物联网平台的物模型通信、OTA升级、任务管理等功能,必须使用的Topic。
物模型Topic:物模型是对设备实际功能的抽象,从属性、服务和事件三个维度,分别描述了该实体是什么、能做什么、能提供什么信息。例如智能风扇的开关状态是属性,开关的操作是服务,报警是事件。什么是物模型。
自定义Topic:如果物模型不能满足业务需求,可以使用自定义Topic,自定义Topic的前三个类目/ProductKey/${deviceName}/user已固定。使用自定义Topic通信。
基础通信Topic和物模型Topic由物联网平台定义,以/sys、/ota或/shadow开头。使用物模型Topic通信,需要先在产品下创建物模型。
物联网中的预定义Topic:
- 基础通信Topic,以OTA升级为例:
设备上报OTA模块版本,数据上行。
Topic:/ota/device/inform/${productKey}/${deviceName}。
物联网平台推送OTA升级包信息,数据下行。
Topic:/ota/device/upgrade/${productKey}/${deviceName}。
设备上报升级进度,数据上行。
Topic:/ota/device/progress/${productKey}/${deviceName}。
设备请求OTA升级包信息,数据上行。
请求Topic:/sys/${productKey}/${deviceName}/thing/ota/firmware/get。
响应Topic:/sys/${productKey}/${deviceName}/thing/ota/firmware/get_reply。
设备请求下载文件分片,升级包下载协议为MQTT时,设备端获取OTA升级包信息后,可通过以下Topic分片下载OTA升级包文件。
请求Topic:/sys/${productKey}/${deviceName}/thing/file/download
响应Topic:/sys/${productKey}/${deviceName}/thing/file/download_reply
与物模型的结合
物模型通信Topic:
设备上报属性:
Topic和数据格式(上行,透传格式数据):
- 请求Topic:/sys/${productKey}/${deviceName}/thing/model/up_raw
- 响应Topic:/sys/${productKey}/${deviceName}/thing/model/up_raw_reply
Topic和数据格式(上行,非透传格式数据,Alink JSON):
- 请求Topic:/sys/${productKey}/${deviceName}/thing/event/property/post
- 响应Topic:/sys/${productKey}/${deviceName}/thing/event/property/post_reply
设置设备属性:下发指令到设备
Topic和数据格式(下行):
透传:
- 请求Topic:/sys/${productKey}/${deviceName}/thing/model/down_raw
- 响应Topic:/sys/${productKey}/${deviceName}/thing/model/down_raw_reply
Alink JSON:
- 请求Topic:/sys/${productKey}/${deviceName}/thing/service/property/set
- 响应Topic:/sys/${productKey}/${deviceName}/thing/service/property/set_reply
设备上报事件:(上行)
透传:
- 请求Topic:/sys/${productKey}/${deviceName}/thing/model/up_raw
- 响应Topic:/sys/${productKey}/${deviceName}/thing/model/up_raw_reply
Alink JSON:
默认模块:
请求Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post
响应Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.event.identifier}/post_reply
自定义:
Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.functionBlockId}:${tsl.event.identifier}/post(请求)
Topic:/sys/${productKey}/${deviceName}/thing/event/${tsl.functionBlockId}:${tsl.event.identifier}/post_reply(响应)
设备服务调用(异步调用):
Topic和数据格式(下行):
透传:
请求Topic:/sys/${productKey}/${deviceName}/thing/model/down_raw
响应Topic:/sys/${productKey}/${deviceName}/thing/model/down_raw_reply
Alink JSON:
默认:
请求Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier}
响应Topic:/sys/${productKey}/${deviceName}/thing/service/${tsl.service.identifier}_reply
自定义:
/sys/${productKey}/${deviceName}/thing/service/${tsl.functionBlockId}:${tsl.service.identifier}
/sys/${productKey}/${deviceName}/thing/service/${tsl.functionBlockId}:${tsl.service.identifier}_reply
网关批量上报数据:网关类型的设备可以批量上报属性和事件,也可以代其子设备批量上报属性和事件。
- 一次最多可上报200个属性,20个事件。
- 一次最多可为20个子设备上报数据。
Topic和数据格式(上行):
透传:
请求Topic:/sys/${productKey}/${deviceName}/thing/model/up_raw
响应Topic:/sys/${productKey}/${deviceName}/thing/model/up_raw_reply
Alink JSON:
请求Topic:/sys/${productKey}/${deviceName}/thing/event/property/pack/post
响应Topic:/sys/${productKey}/${deviceName}/thing/event/property/pack/post_reply
物模型历史数据上报:
Topic和数据格式(上行):
请求Topic:/sys/${productKey}/${deviceName}/thing/event/property/history/post
响应Topic:/sys/${productKey}/${deviceName}/thing/event/property/history/post_reply
设备批量上报属性、事件:
Topic和数据格式(上行):
请求Topic:/sys/${productKey}/${deviceName}/thing/event/property/batch/post
响应Topic:/sys/${productKey}/${deviceName}/thing/event/property/batch/post_reply
5. 保留消息(Retained Message)
MQTT允许发送者指定消息是否为保留消息。如果一个消息被标记为保留,那么当新的订阅者订阅该主题时,他们将立即接收到这个保留消息,而不需要等待下一个消息发布。
6. 遗嘱消息(Will Message)
客户端在连接时可以指定一个遗嘱消息。如果客户端意外断开连接,服务器将自动向客户端订阅的主题发送这个遗嘱消息。
7. 安全机制
- 保活时间:当设备发起连接时会向物联网平台发送CONNECT消息,物联网平台使用CONNACK消息进行响应并保持连接,设备在保活时间间隔内至少需要发送一次报文,否则物联网平台会断开与设备的连接。
MQTT支持多种安全机制,包括:
- TLS/SSL:加密传输,保护数据安全。
- 用户认证:通过用户名和密码进行认证。
- 访问控制:限制客户端对特定主题的访问权限。
8. 会话管理
MQTT支持会话管理,允许客户端在断开连接后重新连接时,恢复之前的状态。会话可以存储订阅信息和未确认的消息。
-
在物联网平台上使用MQTT5.0时,会引入一个会话过期的概念:
设备与物联网平台保持连接时会形成会话状态,会话状态包括订阅的Topic、保留消息、遗嘱消息、平台缓存的QoS1消息等。会话过期是指当设备和物联网平台断开连接,过期后会话会被删除。
- 在MQTT 3.1.1版本中,没有明确的会话过期概念,只有cleanSession决定设备重新连接时是否继续之前的会话状态信息。一个会话要么在断开连接时被清除,要么会一直保留直到设备重新连接物联网平台。
- cleanSession = true:建连时删除会话,设备需要重新订阅topic,也不会收到物联网平台缓存的QoS1消息。
- cleanSession = false:建连时保留会话,设备不需要重新订阅topic,会收到物联网平台缓存的QoS1消息。
- 在MQTT 5.0中,明确引入会话过期的概念,用cleanStart替换cleanSession,增加会话过期间隔属性Session Expiry Interval。这两个参数提供了比MQTT 3.1.1 中的 cleanSession 更精细的会话控制,可以在设备断开连接后的一段时间内保留会话状态,也可以在不需要会话时删除会话,节约云端的资源开发,避免收到不符预期的消息。
- cleanStart是二进制标志位,在设备重新连接物联网平台时,是否开始一个新的会话,并清除任何现有的会话状态信息。
- cleanStart=true:建连时删除之前的会话,设备端需要重新订阅topic,也不会收到物联网平台缓存的QoS1消息。
- cleanStart=false:如果会话没被删除,则继续使用之前的会话。在设备断开连接后,会话被保留的时长为Session Expiry Interval。如果设备在保留时长内重新连接物联网平台,则不需要重新订阅topic,会收到物联网平台缓存的QoS1消息。如果设备没有在保留时长内重新连接,则会话被删除,设备需要重新订阅Topic,不会收到物联网平台缓存的QoS1消息。
- Session Expiry Interval代表时间间隔,单位为秒。在这个时间间隔内,设备断开连接后,物联网平台会保留会话状态。如果不设置,时间间隔默认为0。如果设置为0xFFFFFFFF,时间间隔为无限长。
- 根据会话过期间隔属性Session Expiry Interval和cleanStart的不同取值,会出现以下四种情况:
- cleanStart=true且Session Expiry Interval=0。设备断开连接时立即清理会话,设备重新连接时需要建立新的会话。
- cleanStart=true且Session Expiry Interval=∞,与情况一的结果相同。只要cleanStart=true,设备就会在重新连接时建立新的会话,无论Session Expiry Interval取值多少。
- cleanStart=false,Session Expiry Interval>0但小于设备断开的时间间隔。会话保留的时间较短,在设备重新连接前物联网平台,会话已被删除。
- cleanStart=false,Session Expiry Interval=∞。会话保留的时间无限长,设备重新连接后继续使用之前的会话。
对于车辆等持续移动的设备,如果经常清除会话,会导致频繁的订阅。这种情况适用于上图的情况3,如果设备在一定时间内重连就复用会话,当设备长时间不能连接时清除会话,避免接收处理过期的消息。对于POS机、播报音箱等金融设备,对消息的到达率要求非常高,适用于上图的情况4。会话从创建到结束保持一致,不会丢失订阅关系和消息。对于广告屏设备,持续更新播放新的广告内容,不需要接收过期消息,适用于上图的情况1。不保留会话,可以避免收到无效过期的内容,也可以节约云端的资源消耗。
9. 网络优化
MQTT协议设计考虑了网络的不稳定性。它通过减少消息大小和优化重传机制,适应低带宽和高延迟的网络环境。
MQTT因其灵活性和高效性,成为物联网和移动应用中广泛使用的一种通信协议。
接入物联网平台进行模拟
- 可以使用MQTT.fx接入物联网平台进行模拟
获取mqtt的连接参数
定义物模型:
设置参数
Profile Name | 输入您的自定义名称iot connection。 |
Profile Type | MQTT服务器连接,选择MQTT Broker。 |
Broker Address | MQTT接入域名,对应《前提条件》中已获取的mqttHostUrl值:a1***.iot-as-mqtt.cn-shanghai.aliyuncs.com。
此处仅输入域名,无需携带端口号。 |
Broker Port | 设置为1883。 |
Client ID | MQTT的协议字段。 固定格式:${ClientId}|securemode=${Mode},signmethod=${SignMethod}|timestamp=${timestamp}|。 输入clientId值:a1***.device1|securemode=2,signmethod=hmacsha256,timestamp=2524608000000|。 参数说明:
重要 该值需自定义,长度在64个字符以内。若为设备的ID信息,建议使用您设备的MAC地址或SN码,方便您识别区分不同的设备。
物联网平台提供的连接参数中${ClientId}默认为${ProductKey} + '.' + ${DeviceName}组成的字符串,${Mode}默认为2,${SignMethod}默认为hmacsha256,您可根据需要修改。 重要
|
General | 使用默认值。 |
单击User Credentials,选中Use Username/Password复选框,设置User Name和Password。
TLS直连模式(即securemode=2)下,单击SSL/TLS,选中Enable SSL/TLS,设置Protocol为TLSv1.2。
设置完成后,单击右下角的OK。
单击Connect。右侧亮绿灯,表示连接成功。
使用自定义Topic通信:
上行通信:设备向物联网发信息:
在MQTT.fx上,单击Publish,在Publish文本框中,输入具有发布权限的Topic:/a1***/device1/user/update/error。
在文本编辑页面,输入要发送的消息内容,然后单击Publish。
登录物联网平台控制台,在对应实例下的日志服务页面,查看设备到云消息日志消息。
下行通信:设备通过订阅获取到物联网平台下发的消息
在MQTT.fx上单击Subscribe,在Subscribe文本框中,输入具有订阅权限的Topic:/a1***/device1/user/get
单击Subscribe。订阅成功后,该Topic会显示在列表中。
登录物联网平台控制台,在对应实例下,选择设备管理 > 设备。
单击设备对应操作列的查看,进入设备详情页面。
单击Topic列表页签,单击已订阅Topic对应操作列的发布消息。
输入消息内容,例如This is a test .,单击确认。
回到MQTT.fx上,查看接收到的消息。
- 使用物模型通信Topic通信:
设备上报属性:(需要有发布权限,上行)
在MQTT.fx上单击Subscribe,在Subscribe文本框中,输入具有订阅权限的Topic:/sys/a1****/device1/thing/event/property/post_reply。
在MQTT.fx上单击Publish,在Publish文本框中,输入具有发布权限的Topic:/sys/a1****/device1/thing/event/property/post。
在文本编辑页面,输入要上报的属性数据,然后单击Publish。
设备上报属性数据的格式,需符合标准Alink JSON格式。设备上报属性。上报属性LightCurrent和LightSwitch数据。
在MQTT.fx上单击Subscribe,查看物联网平台返回给设备的响应消息。
如下图所示,设备上报属性成功。
登录物联网平台控制台,在对应实例下,选择设备管理 > 设备。
单击设备对应操作列的查看,在设备详情页面单击物模型数据,查看设备数据。
设置设备属性:(需要模拟设备有订阅权限,下行)
在MQTT.fx上单击Subscribe,在Subscribe文本框中,输入具有订阅权限的Topic:/sys/a1****/device1/thing/service/property/set。
登录物联网平台控制台,在对应实例下,选择监控运维 > 在线调试。
选择要调试的设备,然后在属性调试页签下,设置主灯开关为关闭-0。
单击设置,发送指令。
在MQTT.fx上的Subscribe页签下,查看设备接收的消息。
可以通过查看日志对模拟设备的上行和下行操作进行查看。可以看到错误信息。