

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# coreMQTT 双向身份验证演示
<a name="mqtt-demo-ma"></a>

**重要**  <a name="deprecation-message-demo"></a>
该演示托管在已弃用的 Amazon-FreeRTOS 存储库中。当您创建新项目时，我们建议[从此处开始](freertos-getting-started-modular.md)。如果您已经有一个基于现已弃用的 Amazon-FreeRTOS 存储库的 FreeRTOS 项目，请参阅 [Amazon-FreeRTOS Github 存储库迁移指南](github-repo-migration.md)。

## 简介
<a name="mqtt-demo-ma-introduction"></a>

coreMQTT 双向身份验证演示项目展示了如何使用在客户端与服务器之间具有双向身份验证的 TLS 建立与 MQTT 代理的连接。此演示使用基于 mbedTLS 的传输接口实现来建立经过服务器和客户端身份验证的 TLS 连接，并演示了 [QoS 1](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html#_Toc442180914) 级别的 MQTT 订阅发布工作流程。它会订阅主题筛选条件，然后发布到与筛选条件匹配的主题，并等待从 QoS 1 级别收到服务器发回的消息。这种向代理发布消息并从代理接收相同消息的循环过程会无限期地重复。本演示中的消息按照 QoS 1 发送，这样可以保证至少有一次按照 MQTT 规范传递。

**注意**  
要设置和运行 FreeRTOS 演示，请按照[开始使用 FreeRTOS](freertos-getting-started.md)中的步骤操作。

## 源代码
<a name="mqtt-demo-ma-source-code"></a>

演示源文件已命名`mqtt_demo_mutual_auth.c`，可以在`{{freertos}}/demos/coreMQTT/`目录和[ GitHub](https://github.com/aws/amazon-freertos/blob/main/demos/coreMQTT/mqtt_demo_mutual_auth.c)网站上找到。

## 功能
<a name="mqtt-demo-ma-functionality"></a>

该演示创建了一个应用程序任务，该任务循环访问一组示例，这些示例演示如何连接代理、订阅代理上的主题、发布到代理上的主题，最后断开与代理的连接。该演示应用程序会订阅一个主题的消息，也会向同一个主题发布消息。每次演示向 MQTT 代理发布消息时，代理都会向演示应用程序发送相同的消息。

成功完成演示将生成类似于以下图像的输出。

![MQTT 演示终端在成功完成后的输出](http://docs.amazonaws.cn/freertos/latest/userguide/images/coremqtt-mad-output.png)


 Amazon IoT 控制台将生成类似于下图的输出。

![MQTT 演示控制台在成功完成后的输出](http://docs.amazonaws.cn/freertos/latest/userguide/images/coremqtt-mad-console.png)


## 使用指数回退和抖动重试逻辑
<a name="mqtt-demo-ma-retry-logic"></a>

[ prvBackoffFor重试](https://github.com/aws/amazon-freertos/blob/main/demos/coreMQTT/mqtt_demo_mutual_auth.c#L671-L717)函数显示如何通过指数退避和抖动重试服务器失败的网络操作（例如 TLS 连接或 MQTT 订阅请求）。该函数可计算下一次重试尝试的回退周期，如果重试尝试未用完，则执行回退延迟。由于计算退避周期需要生成随机数，因此该函数使用 PKCS11 模块生成随机数。如果供应商平台支持，则使用该 PKCS11 模块允许访问真随机数生成器 (TRNG)。我们建议您在随机数生成器中加入特定于设备的熵源，这样可以降低设备在连接重试过程中发生冲突的可能性。

## 连接到 MQTT 代理
<a name="mqtt-demo-ma-connecting"></a>

该[ prvConnectToServerWithBackoffRetries](https://github.com/aws/amazon-freertos/blob/main/demos/coreMQTT/mqtt_demo_mutual_auth.c#L721-L782)函数尝试与 MQTT 代理建立相互身份验证的 TLS 连接。如果连接失败，则会在回退周期后重试。回退周期将呈指数级增长，直到达到最大尝试次数或达到最大回退周期。`BackoffAlgorithm_GetNextBackoff` 函数提供指数级增长的回退值，并在达到最大尝试次数后返回 `RetryUtilsRetriesExhausted`。如果在配置的尝试次数后仍无法建立与代理的 TLS 连接，则 `prvConnectToServerWithBackoffRetries` 函数将返回失败状态。

[prvCreate MQTTConnection WithBroker](https://github.com/aws/amazon-freertos/blob/main/demos/coreMQTT/mqtt_demo_mutual_auth.c#L785-L848) 函数演示了如何通过干净的会话与 MQTT 代理建立 MQTT 连接。它使用 TLS 传输接口，该接口在 `FreeRTOS-Plus/Source/Application-Protocols/platform/freertos/transport/src/tls_freertos.c` 文件中实现。请记住，我们正在 `xConnectInfo` 中为代理设置保持活动状态的秒数。

下一个函数展示了如何使用 `MQTT_Init` 函数在 MQTT 环境中设置 TLS 传输接口和时间函数，还展示了事件回调函数指针 (`prvEventCallback`) 是如何设置的。该回调用于报告传入的消息。

## 订阅 MQTT 主题
<a name="mqtt-demo-ma-subscribing"></a>

p [rv MQTTSubscribe WithBackoffRetries](https://github.com/aws/amazon-freertos/blob/main/demos/coreMQTT/mqtt_demo_mutual_auth.c#L871-L969) 函数演示如何在 MQTT 代理上订阅主题过滤器。该示例演示了如何订阅一个主题筛选条件，还可以在同一个订阅 API 调用中传递主题筛选条件列表来订阅多个主题筛选条件。此外，对于 `RETRY_MAX_ATTEMPTS`，如果 MQTT 代理拒绝订阅请求，则订阅将以指数回退的方式重试。

## 向主题发布
<a name="mqtt-demo-ma-publishing"></a>

p [rv MQTTPublish ToTopic](https://github.com/aws/amazon-freertos/blob/main/demos/coreMQTT/mqtt_demo_mutual_auth.c#L972-L1004) 函数演示如何在 MQTT 代理上发布到某个主题。

## 接收传入的消息
<a name="mqtt-demo-ma-receiving"></a>

如前所述，该应用程序会在连接到代理之前注册一个事件回调函数。`prvMQTTDemoTask` 函数调用 `MQTT_ProcessLoop` 函数来接收传入的消息。当收到传入的 MQTT 消息时，它会调用应用程序注册的事件回调函数。该[ prvEventCallback](https://github.com/aws/amazon-freertos/blob/main/demos/coreMQTT/mqtt_demo_mutual_auth.c#L1139-L1154)函数就是这样一个事件回调函数的示例。 `prvEventCallback`检查传入的数据包类型并调用相应的处理程序。在下面的示例中，该函数要么调用 `prvMQTTProcessIncomingPublish()` 来处理传入的发布消息，要么调用 `prvMQTTProcessResponse()` 来处理确认消息 (ACK)。

## 处理传入的 MQTT 发布数据包
<a name="mqtt-demo-ma-processing"></a>

[prv MQTTProcess IncomingPublish](https://github.com/aws/amazon-freertos/blob/main/demos/coreMQTT/mqtt_demo_mutual_auth.c#L1108-L1135) 函数演示如何处理来自 MQTT 代理的发布数据包。

## 取消订阅主题
<a name="mqtt-demo-ma-unsubscribing"></a>

该工作流程的最后一步是取消订阅主题，这样代理就不会从 `mqttexampleTOPIC` 发送任何已发布的消息。这是函数 [prv MQTTUnsubscribe FromTopic](https://github.com/aws/amazon-freertos/blob/main/demos/coreMQTT/mqtt_demo_mutual_auth.c#L1007-L1043) 的定义。

## 更改演示中使用的根 CA
<a name="mqtt-demo-ma-root-ca"></a>

默认情况下，FreeRTOS 演示使用 Amazon Root CA 1 证书（RSA 2048 位密钥）向服务器进行身份验证。 Amazon IoT Core 您可以使用其他 [CA 证书来进行服务器身份验证](https://docs.amazonaws.cn/iot/latest/developerguide/server-authentication.html#server-authentication-certs)，包括 Amazon Root CA 3 证书（ECC 256 位密钥）。要更改 coreMQTT 双向身份验证演示的根 CA，请执行以下操作：

1. 在文本编辑器中，打开 `{{freertos}}/vendors/{{vendor}}/boards/{{board}}/aws_demos/config_files/mqtt_demo_mutual_auth_config.h`文件。

1. 在文件中找到以下行。

   ```
    * #define democonfigROOT_CA_PEM    "...insert here..." 
   ```

   取消注释此行，如有必要，将其移到注释块末尾的 ` */` 之后。

1. 复制要使用的 CA 证书，然后将其粘贴到文本 `"...insert here..."` 处。结果应该类似以下示例。

   ```
   #define democonfigROOT_CA_PEM   "-----BEGIN CERTIFICATE-----\n"\
   "MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5\n"\
   "MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g\n"\
   "Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG\n"\
   "A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg\n"\
   "Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl\n"\
   "ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j\n"\
   "QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr\n"\
   "ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr\n"\
   "BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM\n"\
   "YyRIHN8wfdVoOw==\n"\
   "-----END CERTIFICATE-----\n"
   ```

1. （可选）您可以更改其他演示的根 CA。对每个 `{{freertos}}/vendors/{{vendor}}/boards/{{board}}/aws_demos/config_files/{{demo-name}}_config.h` 文件重复步骤 1 到 3。