从零吃透 MQTT 通信|第 10 章 阿里云 / 腾讯云 MQTT 设备完整对接实战,三元组、签名、设备上云调试
2026/9/14 20:39:15 网站建设 项目流程

专栏说明:前面章节完成裸机 MQTT 协议栈、FreeRTOS 多任务框架、JSON 业务报文封装。自己搭建私有 MQTT 服务器调试比较麻烦,国内项目大多直接使用公有物联网云平台。公有云 MQTT 和标准 MQTT 协议并不完全等同,增加了设备身份鉴权机制,不能直接随便填用户名密码连接。

本章重点讲解阿里云 IoT、腾讯云 IoT‑Explorer 设备认证原理、三元组、MQTT 连接签名计算、设备接入流程,给出 C 语言签名代码,同时整理上云调试排错思路,帮助读者把单片机设备真正接入公有云平台。

0 公有云 MQTT 和标准 MQTT 的差异

标准 MQTT 协议 CONNECT 报文支持 clientId、username、password,没有规定内容格式,私有服务器可以随意填写。 但是阿里云、腾讯云这类物联网平台,不允许直接随便填写账号密码连接,平台采用非对称 / 哈希签名做设备身份校验。

关键概念:

  • ClientId:设备客户端 ID,公有云平台有格式约束;
  • Username:平台规定拼接出来的用户名;
  • Password:不是明文密码,是通过密钥、时间戳计算出来的签名值

重点:设备密钥是敏感信息,量产固件不要硬编码明文密钥,推荐存储在内部 Flash 或者外部加密存储芯片。

1 阿里云 IoT 平台接入(MQTT 3.1.1)

1.1 设备三元组概念

在阿里云物联网平台创建设备后,会得到设备三元组:

  • ProductKey:产品标识,同一产品下设备共用;
  • DeviceName:设备名称,单个设备唯一;
  • DeviceSecret:设备密钥,参与签名计算,务必保密

1.2 连接参数规则

  1. MQTT 接入域名:${ProductKey}.iot‑cn‑shanghai‑a.aliyuncs.com,端口:1883(TCP)、8883(TLS 加密)
  2. ClientId 格式:${DeviceName}|timestamp=${expire},securemode=2,signmethod=hmacsha1|
  3. Username:${DeviceName}&${ProductKey}
  4. Password:Hmac‑SHA1 签名结果

签名源字符串构造规则:

clientId${DeviceName}deviceName${DeviceName}productKey${ProductKey}timestamp${expireTime}

使用DeviceSecret作为密钥,对源字符串做 HMAC‑SHA1,输出做 Base64 编码得到 password。

expire 代表签名过期时间,单位毫秒;建议设置当前时间 + 30601000,签名半小时有效。设备必须内置 RTC 时间,如果没有 RTC,需要通过 NTP 获取网络时间,时间错误会直接鉴权失败。

1.3 HMAC‑SHA1 + Base64 C 语言示例片段

嵌入式需要移植 HMAC‑SHA1、Base64 工具函数,STM32 可以调用硬件 CRC 或者软件实现。

/** * @brief 阿里云MQTT密码生成 */ int ali_gen_password(char *productKey,char *deviceName,char *deviceSecret,uint32_t expire_ms,char *outPwd,int maxLen) { char srcStr[256]; char signBin[20]; char base64Buf[128]; /* 拼接签名原文 */ sprintf(srcStr,"clientId%sdeviceName%sproductKey%stimestamp%lu", deviceName,deviceName,productKey,expire_ms); /* HMAC‑SHA1,密钥deviceSecret,输入srcStr,输出20字节摘要signBin */ hmac_sha1((uint8_t*)deviceSecret,strlen(deviceSecret), (uint8_t*)srcStr,strlen(srcStr),signBin); /* 摘要base64编码得到password */ int baseLen = base64_encode(signBin,20,base64Buf,sizeof(base64Buf)); if(baseLen <=0 || baseLen >= maxLen) return -1; strcpy(outPwd,base64Buf); return 0; }

CONNECT 报文填入生成好的 clientId、username、password,执行 MQTT 连接。

1.4 阿里云平台 Topic 规则

平台会自动分配系统 Topic,设备只能向授权 Topic 发布订阅:

  • 设备上报:/${ProductKey}/${DeviceName}/thing/event/property/post
  • 平台下发指令:/${ProductKey}/${DeviceName}/thing/service/property/set

上报属性 JSON 是阿里云物模型规定格式:

{ "id":"123456", "params":{ "Temperature":25.6, "Humidity":62.1 }, "method":"thing.event.property.post" }

不要随意自定义 Topic,需要在阿里云控制台提前新建并给设备授权权限,否则发布报文会被平台拒绝。

2 腾讯云 IoT Explorer MQTT 接入

2.1 腾讯云设备信息

腾讯云设备信息:ProductID、DeviceName、DeviceSecret。 接入域名:${ProductID}.iotcloud.tencentdevices.com,端口 1883/8883。

  • ClientId = \({ProductID}\){DeviceName}
  • Username:${DeviceName};${ProductID};${timestamp};20100406
  • Password:HMAC‑SHA256 签名之后 base64 结果

签名源串:

${ProductID}${DeviceName}${timestamp}

密钥为 DeviceSecret,HMAC‑SHA256 计算摘要,Base64 输出 password。 timestamp 是秒级 Unix 时间戳。

腾讯云同样依赖设备系统时间,时间偏差过大鉴权失败。

2.2 腾讯云系统 Topic

  • 属性上报:$thing/up/property/${ProductID}/${DeviceName}
  • 平台下发指令:$thing/down/property/${ProductID}/${DeviceName}

3 嵌入式设备无 RTC 时钟如何解决签名时间问题

公有云签名强依赖 Unix 时间,很多单片机没有硬件 RTC: 方案 1:设备上电后,通过 UDP NTP 客户端获取网络时间,拿到时间戳之后再计算 MQTT 签名发起连接; 方案 2:部分平台支持离线短时效签名,不推荐;

注意:NTP 请求要在 Wi‑Fi/4G 网络链路通之后,MQTT 连接之前完成。

4 设备上云完整业务流程

  1. 设备上电初始化外设;
  2. Wi‑Fi/4G 模组连接网络,保证 IP 网络通畅;
  3. NTP 获取 Unix 时间戳;
  4. 根据云平台规则计算 ClientId、Username、Password;
  5. MQTT CONNECT 报文携带鉴权参数连接云平台;
  6. 收到 CONNACK 0 代表连接成功;
  7. 订阅平台下发指令系统 Topic;
  8. 设备定时上报物模型 JSON;
  9. 接收云端下发指令,解析 JSON 执行动作;
  10. 异常断线执行阶梯退避重连,重连后重新订阅系统 Topic。

5 公有云对接高频踩坑清单

  1. 签名参数拼接错误:字符串顺序、大小写、字段写错,返回 CONNACK 拒绝连接。
  2. 设备本地时间不准:时间超前或者滞后,签名过期,鉴权失败。
  3. Topic 没有授权:自定义 Topic 没有控制台授权,publish 返回失败,设备收不到下发消息。
  4. 三元组密钥泄露:固件硬编码密钥,固件被逆向会导致设备被劫持;量产建议加密存储。
  5. cleanSession 参数:公有云设备一般 cleanSession=1;重连之后必须重新订阅系统 topic。
  6. 明文 1883 端口网络环境:运营商可能劫持过滤 1883 端口,量产环境建议开启 TLS 加密 8883 端口。
  7. 报文 payload 格式不符合物模型规范:连接成功但是平台看不到解析后的数据。
  8. 设备重连风暴:网络抖动大量设备同时重连冲击云平台,必须使用阶梯退避重连策略。

6 调试工具推荐

  1. MQTTX 桌面客户端:填入三元组生成参数模拟设备,先在电脑调通云平台交互逻辑,再移植单片机。
  2. 云平台在线日志:开启设备日志,查看设备连接、发布订阅拒绝原因。
  3. 串口打印:打印完整 clientId/username/password(调试阶段,量产关闭),对比电脑端 MQTTX 参数。

7 TLS 加密说明

1883 端口是明文 MQTT,网络抓包可以看到全部报文,密钥、payload 全部暴露,只适合调试。 量产环境使用 8883 端口 TLS 加密,单片机需要移植 mbed‑tls 库,完成 TLS 握手之后传输 MQTT 报文。TLS 会增加 RAM/ROM 占用,RAM 小的 MCU 谨慎评估。

本章总结

本章完成公有云 MQTT 接入实战,理解公有云不是直接填写明文账号密码,而是基于设备密钥 + 时间戳做 HMAC 签名鉴权。同时梳理阿里云、腾讯云接入参数、Topic 规则,以及无 RTC 设备时间解决方案。

到这里,从 MQTT 协议理论、裸机协议栈、RTOS 工程、JSON 业务、公有云接入全部完成。下一章做项目常见问题、调试验证、性能优化,以及 OTA 升级基础概念。

下一章预告:第 11 章 MQTT 项目调试验证、性能优化、常见疑难问题、OTA 升级基础

💖 点赞 + 收藏 + 关注,MQTT 物联网上云系列持续更新!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询