coreMQTT 演示(带 TLS 服务器身份验证)
coreMQTT是一个 MIT 授权的开源 MQTT 客户端 C 库,适用于基于微控制器和小型微处理器的 IoT 设备。
注意:我们建议使用相互身份验证( IoT MQTT客户端和服务器
相互进行身份验证)——在构建任何物联网 (IoT) 应用程序时。此页面上的演示
展示了未经客户端身份验证的加密通信,仅用于教育目的。它不适用于
生产用途。
单线程 VS 多线程
coreMQTT 有两种使用模式,单线程和多线程(多任务)。在多线程应用程序中,
仅在一个线程上使用 MQTT 库(如本页记录的演示那样)
等同于单线程用例。单线程用例要求应用程序编写者
对 MQTT 库进行重复的显式调用。多线程使用案例可以
在后台的 agent(或守护进程)任务中执行 MQTT 协议。在 agent 任务中执行 MQTT 协议
使应用程序编写者无需显式托管任何 MQTT 状态或调用 MQTT_ProcessLoop()
API 函数。
使用 agent 任务还可以让多个应用程序任务共享单个 MQTT 连接,
无需互斥锁之类的同步基元。
演示简介
共有三个示例项目介绍 “TLS 简介”
页面上描述的概念,此示例项目是其中之一。第一个示例演示了未加密的
MQTT 通信。第二个示例(即本页面上的示例)在第一个示例的基础上引入服务器身份验证( IoT
客户端对其所连接的 MQTT 服务器进行身份验证)。第三个示例
在第二个示例的基础上引入强力相互身份验证(MQTT 服务器也会对其所连接的 客户端进行身份验证)。
此演示不使用相互身份验证,因此仅用于练习。
此 MQTT 演示使用基于 mbedTLS 的网络传输接口实现,
首先与 MQTT 代理建立服务器验证的 TLS 连接,
然后演示 MQTT 在 QoS 2 级的订阅-发布工作流程。演示中,代理通过订阅单个主题过滤器回传消息,
然后发布到同一个主题。每次发布后,
它都会等待从 QoS 2 级服务器接收回传信息。这种向代理发布信息
并从代理接收相同信息的循环会无限期地重复。此演示中的消息在 QoS 2 上发送,确保消息仅
传送一次。
此 MQTT 基础演示项目使用 FreeRTOS
Windows 移植,从而可以在 Windows 上使用 Visual Studio 免费社区版构建和评估它,无需任何特定的 MCU 硬件。
源代码组织
此演示项目的名称是 mqtt_basic_tls_demo.sln,可以在 FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS
目录中找到,位于主 FreeRTOS 下载中,(也可在下载页面链接的 Github 中找到)。
配置演示项目
此演示使用 FreeRTOS-Plus-TCP TCP/IP 堆栈。按照
为 TCP/IP 入门项目提供的说明进行操作,
以确保您:
- 安装了必要的
组件(如 WinPCap)。
- 设置一个静态
或动态 IP 地址、网关地址和网络掩码(可选)。
- 设置一个 MAC
地址(可选)。
- 在您的主机上选择
以太网网络接口。
- 最重要的是,
在尝试运行 MQTT 演示之前,请测试您的网络连接。
所有这些设置都应在 MQTT 演示项目中执行,而非在同一页面中引用的 TCP/IP 入门项目中执行!
传递时,TCP/IP 堆栈被配置为使用动态 IP 地址。
配置 MQTT 代理连接
备选方案 1:使用公开托管的 Mosquitto MQTT 代理( web 托管):
想要与 Mosquitto 公开托管的 MQTT 代理进行通信,请按照下列步骤进行操作:
- 打开
FreeRTOS/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/demo_config.h
的本地副本
- 设置下列两个常量:
#define democonfigMQTT_BROKER_ENDPOINT "test.mosquitto.org"
#define democonfigMQTT_BROKER_PORT (8883)
- 将常量
# democonfigROOT_CA_PEM
(服务器的 CA 根证书)设置为
https://test.mosquitto.org 主页连接的 PEM 证书 。该证书
要以字符串的形式进行粘贴,因此它将如下所示:
#define democonfigROOT_CA_PEM \
"-----BEGIN CERTIFICATE-----\n"\
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"\
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"\
"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\n"\
"... etc. .......................................................\n"\
"-----END CERTIFICATE-----"
如果演示连接到具有 DHCP 服务和互联网接入的网络,则此设置应有效。请注意,
请注意,FreeRTOS Windows 移植仅适用于有线以太网适配器(可以是虚拟以太网适配器)。
应使用单独的 MQTT 客户端(如 MQTT.fx)
来测试从您的主机到公共 MQTT 代理的 MQTT 连接。
注意:Mosquitto 是一个开源 MQTT 消息代理,支持 MQTT 5.0、3.1.1 和 3.1 版本。它是
Eclipse 基金会的一部分,是一个 Eclipse IoT 项目。test.mosquitto.org
MQTT 代理不隶属于
FreeRTOS,也不由其维护,可能随时不可用。此外,此代理使用的服务器身份验证基于
1024 位 RSA,
所以不推荐用于生产目的。请勿从您的设备
向 MQTT 代理发送任何机密信息。
备选方案 2:使用本地托管的 Mosquitto MQTT 消息代理(主机)
Mosquitto 代理也可以在本地运行,无论是在您的主机上(用于构建演示应用程序的机器),还是在
您本地网络的另一台计算机上。请按以下步骤操作:
-
- 请按照 https://mosquitto.org/download/上的说明在本地下载和安装 Mosquitto。
- 打开 Mosquitto 安装目录中的 “mosquitto.conf”,并设置下列配置:
- per_listener_settings: true
- port: 8883
- allow_anonymous: false
- cafile: ./mosquitto/config/ca.crt
- certfile: ./mosquitto/config/server.crt
- keyfile: ./mosquitto/config/server.key
- tls_version: tlsv1.2
注:上述配置中的 “cafile”、“certfile”、“keyfile” 分别指本地生成的 CA 证书、服务器证书、
服务器密钥。它们都可以使用 OpenSSL 生成。想要了解更多信息,请参阅
mosquitto.org 。
- 打开
FreeRTOS/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/demo_config.h
的本地副本
- 添加下列行以设置 democonfigMQTT_BROKER_ENDPOINT 和 democonfigMQTT_BROKER_PORT:
#define democonfigMQTT_BROKER_ENDPOINT "w.x.y.z"
#define democonfigMQTT_BROKER_PORT ( 8883 )
注意: 端口号 8883 是加密 MQTT 的默认端口号。 如果您无法使用该端口
(例如,如果它被您的 IT 安全策略阻止),请把 Mosquitto 使用的端口更改为更高的端口号
(例如,50000 到 55000 范围内的端口号),并相应地设置 mqttexampleMQTT_BROKER_PORT
。
Mosquitto 使用的端口号由 “mosquitto.conf” 中的“端口”参数设置( “mosquitto.conf” 在 Mosquitto 安装目录中)。
选项3 :您选择的 MQTT 代理:
任何支持加密 TCP/IP 通信的 MQTT 代理都可与此演示一起使用。请按以下步骤操作:
- 打开
/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/demo_config.h
的本地副本
- 添加下列行,并设置您所选择的代理:
- #define democonfigMQTT_BROKER_ENDPOINT "your-desired-endpoint"
- #define democonfigMQTT_BROKER_PORT ( 8883 )
- 在
demo_config.h
中设置服务器的 CA 根证书 (#democonfigROOT_CA_PEM
) (可选)
构建演示项目
演示项目的构建方式与 MQTT 基础演示(无 TLS)相同。
- 从 Visual Studio IDE 中打开
FreeRTOS/FreeRTOS-Plus/Demo/coreMQTT_Windows_Simulator/MQTT_Basic_TLS/mqtt_basic_tls_demo.sln
Visual Studio 解决方案文件。
- 在 IDE 的 “Build” 菜单中选择 “Build Solution”。
注意:如果您使用的是 Microsoft Visual Studio 2017 或更早版本,则必须选择与您的版本兼容的 “平台
工具集”:"Project -> RTOSDemos Properties -> Platform Toolset"。
故障排除
注意: 如果设置了常量 #democonfigROOT_CA_PEM,请确保其格式正确。
X509——格式无法识别。
- 确保证书 (#democonfigROOT_CA_PEM) 的开头和结尾如下。
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
PEM - PEM 字符串与预期不符: BASE64 - 输入字符无效。
- 确保证书字符串中没有无效字符,尤其是在复制粘贴内容时。
功能
该演示提供了与基本
MQTT 演示(不含 TLS)相同的功能和结构体,但使用了包含 TLS 的传输接口
来代替明文传输接口。
连接至 MQTT 代理(使用 TLS)
函数 prvConnectToServerWithBackoffRetries()
试图将 TLS 连接到 MQTT 代理。如果
连接失败,则在超时后重试。超时值将呈指数增长,
直到达到最大尝试次数或最大超时值。函数 RetryUtils_BackoffAndSleep()
提供呈指数增长的超时值,并在达到最大尝试次数时返回 RetryUtilsRetriesExhausted
。重试之间的时间差用于确保碰巧同时断开连接的 IoT 设备群
不会在完全相同的时间内尝试重新连接。
static TlsTransportStatus_t prvConnectToServerWithBackoffRetries(
NetworkCredentials_t * pxNetworkCredentials,
NetworkContext_t * pxNetworkContext )
{
TlsTransportStatus_t xNetworkStatus;
RetryUtilsStatus_t xRetryUtilsStatus = RetryUtilsSuccess;
RetryUtilsParams_t xReconnectParams;
pxNetworkCredentials->pRootCa = ( const unsigned char * ) democonfigROOT_CA_PEM;
pxNetworkCredentials->rootCaSize = sizeof( democonfigROOT_CA_PEM );
pxNetworkCredentials->disableSni = democonfigDISABLE_SNI;
RetryUtils_ParamsReset( &xReconnectParams );
xReconnectParams.maxRetryAttempts = MAX_RETRY_ATTEMPTS;
do
{
xNetworkStatus = TLS_FreeRTOS_Connect( pxNetworkContext,
democonfigMQTT_BROKER_ENDPOINT,
democonfigMQTT_BROKER_PORT,
pxNetworkCredentials,
mqttexampleTRANSPORT_SEND_RECV_TIMEOUT_MS,
mqttexampleTRANSPORT_SEND_RECV_TIMEOUT_MS );
if( xNetworkStatus != TLS_TRANSPORT_SUCCESS )
{
xRetryUtilsStatus = RetryUtils_BackoffAndSleep( &xReconnectParams );
}
if( xRetryUtilsStatus == RetryUtilsRetriesExhausted )
{
xNetworkStatus = TLS_TRANSPORT_CONNECT_FAILURE;
}
} while( ( xNetworkStatus != TLS_TRANSPORT_SUCCESS ) &&
( xRetryUtilsStatus == RetryUtilsSuccess ) );
return xNetworkStatus;
}
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.