

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# coreMQTT Agent 連線共用示範
<a name="mqtt-demo-cs"></a>

**重要**  <a name="deprecation-message-demo"></a>
此示範託管在已棄用的 Amazon-FreeRTOS 儲存庫上。我們建議您在建立新專案時從[這裡開始](freertos-getting-started-modular.md)。如果您已經有以現在已棄用之 Amazon-FreeRTOS 儲存庫為基礎的現有 FreeRTOS 專案，請參閱 [Amazon-FreeRTOS Github 儲存庫遷移指南](github-repo-migration.md)。 FreeRTOS 

## 簡介
<a name="mqtt-demo-cs-introduction"></a>

coreMQTT 連線共用示範專案說明如何使用多執行緒應用程式，透過用戶端與伺服器之間的交互身分驗證，使用 TLS 建立與 AWS 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)。

此示範使用執行緒安全佇列來保留命令，以與 MQTT API 互動。此示範中需要注意兩個任務。
+ MQTT 代理程式 （主要） 任務會處理來自命令佇列的命令，而其他任務則會排入佇列。此任務會進入迴圈，在此期間會處理來自命令佇列的命令。如果收到終止命令，此任務將中斷迴圈。
+ 示範子集任務會建立 MQTT 主題的訂閱，然後建立發佈操作並將其推送至命令佇列。這些發佈操作接著會由 MQTT 代理程式任務執行。示範子集任務會等待發佈完成，以執行命令完成回呼表示，然後輸入短暫延遲，再開始下一個發佈。此任務顯示應用程式任務如何使用 coreMQTT Agent API 的範例。

對於傳入發佈訊息，coreMQTT 代理程式會叫用單一回呼函數。此示範也包含訂閱管理員，允許任務指定回呼，以針對已訂閱主題的傳入發佈訊息叫用。在此示範中，客服人員的傳入發佈回呼會叫用訂閱管理員，將發佈發佈到已註冊訂閱的任何任務。

此示範使用具有交互身分驗證的 TLS 連線來連線 AWS。如果網路在示範期間意外中斷連線，則用戶端會嘗試使用指數退避邏輯重新連線。如果用戶端成功重新連線，但代理程式無法繼續先前的工作階段，則用戶端會重新訂閱與上一個工作階段相同的主題。

### 單一執行緒與多執行緒
<a name="mqtt-demo-cs-single-vs-multi"></a>

有兩種 coreMQTT 用量模型：單一執行緒和多執行緒 （多工）。單一執行緒模型僅從一個執行緒使用 coreMQTT 程式庫，並要求您在 MQTT 程式庫中重複進行明確呼叫。多執行緒使用案例可以改為在代理程式 （或協助程式） 任務的背景中執行 MQTT 通訊協定，如此處所述的示範所示。當您在代理程式任務中執行 MQTT 通訊協定時，您不需要明確管理任何 MQTT 狀態或呼叫 `MQTT_ProcessLoop` API 函數。此外，當您使用代理程式任務時，多個應用程式任務可以共用單一 MQTT 連線，而不需要同步基本概念，例如互斥。

## 來源碼
<a name="mqtt-demo-cs-source-code"></a>

示範來源檔案命名為 `mqtt_agent_task.c``simple_sub_pub_demo.c`和 ，可在 `freertos/demos/coreMQTT_Agent/`目錄和 [GitHub](https://github.com/aws/amazon-freertos/tree/main/demos/coreMQTT_Agent/) 網站中找到。

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

此示範會建立至少兩個任務：處理 MQTT API 呼叫請求的主要任務，以及建立這些請求的可設定子任務數量。在此示範中，主要任務會建立子任務、呼叫處理迴圈，並在之後清除。主要任務會建立與子任務之間共用之代理程式的單一 MQTT 連線。子任務會使用代理程式建立 MQTT 訂閱，然後將訊息發佈至該訂閱。每個子任務都會為其發佈使用唯一的主題。

## 主要任務
<a name="mqtt-demo-cs-main-task"></a>

主要應用程式任務 [ RunCoreMQTTAgentDemo](https://github.com/aws/amazon-freertos/blob/main/demos/coreMQTT_Agent/mqtt_agent_task.c#L435-L480) 會建立 MQTT 工作階段、建立子任務，並執行處理迴圈 [ MQTTAgent\$1CommandLoop](https://github.com/aws/amazon-freertos/blob/main/demos/coreMQTT_Agent/mqtt_agent_task.c#L856)，直到收到終止命令為止。如果網路意外中斷連線，示範會重新連線到背景的代理程式，並與代理程式重新建立訂閱。處理迴圈終止後，它會與中介裝置中斷連線。

### 命令
<a name="mqtt-demo-cs-main-task-commands"></a>

當您叫用 coreMQTT 代理程式 API 時，它會建立傳送至代理程式任務佇列的命令，該佇列會在 中處理`MQTTAgent_CommandLoop()`。建立命令時，可能會傳遞選用的完成回呼和內容參數。對應命令完成後，系統會使用傳遞的內容和任何因命令而建立的傳回值來叫用完成回呼。完成回呼的簽章如下所示：

```
typedef void (* MQTTAgentCommandCallback_t )( void * pCmdCallbackContext,
                                              MQTTAgentReturnInfo_t * pReturnInfo );
```

命令完成內容是由使用者定義；在此示範中，它是：[struct MQTTAgentCommandContext](https://github.com/aws/amazon-freertos/blob/main/demos/coreMQTT_Agent/simple_sub_pub_demo.c#L105-L115)。

命令在下列情況下視為已完成：
+ 訂閱、取消訂閱和發佈 QoS > 0：收到對應的確認封包後。
+ 所有其他操作：呼叫對應的 coreMQTT API 後。

命令使用的任何結構，包括發佈資訊、訂閱資訊和完成內容，都必須保持在範圍內，直到命令完成為止。在呼叫完成回呼之前，呼叫任務不得重複使用任何命令的結構。請注意，由於 MQTT 代理程式會叫用完成回呼，因此它會使用代理程式任務的執行緒內容執行，而不是建立命令的任務。處理間通訊機制，例如任務通知或佇列，可用於向呼叫任務發出命令完成的訊號。

### 執行命令迴圈
<a name="mqtt-demo-cs-command-loop"></a>

命令會在 中持續處理`MQTTAgent_CommandLoop()`。如果沒有要處理的命令，迴圈最多會等待`MQTT_AGENT_MAX_EVENT_QUEUE_WAIT_TIME`一個命令新增到佇列，如果沒有新增命令，則會執行 的單一反覆運算`MQTT_ProcessLoop()`。這可確保管理 MQTT Keep-Alive，即使佇列中沒有命令，也會接收任何傳入的發佈。

命令迴圈函數會傳回，原因如下：
+ 命令會傳回 以外的任何狀態碼`MQTTSuccess`。錯誤狀態由命令迴圈傳回，因此您可以決定如何處理它。在此示範中，會重新建立 TCP 連線，並嘗試重新連線。如果有任何錯誤，重新連線可能會在背景中發生，而不需要使用 MQTT 進行其他任務的任何介入。
+ 系統會處理中斷連線命令 （來自 `MQTTAgent_Disconnect`)。命令迴圈會結束，以便 TCP 可以中斷連線。
+ 系統會處理終止命令 （來自 `MQTTAgent_Terminate`)。此命令也會將仍在佇列中或等待確認封包的任何命令標記為錯誤，傳回代碼為 `MQTTRecvFailed`。

### 訂閱管理員
<a name="mqtt-demo-cs-subscription-manager"></a>

由於示範使用多個主題，訂閱管理員是將訂閱主題與唯一回呼或任務建立關聯的便利方式。此示範中的訂閱管理員為單執行緒，因此不應同時供多個任務使用。在此示範中，訂閱管理員函數只會從傳遞給 MQTT 代理程式的回呼函數呼叫，並且只會使用代理程式任務的執行緒內容執行。

## 簡單訂閱發佈任務
<a name="mqtt-demo-cs-sub-pub"></a>

[ prvSimpleSubscribePublishTask ](https://github.com/aws/amazon-freertos/blob/main/demos/coreMQTT_Agent/simple_sub_pub_demo.c#L447-L569)的每個執行個體都會建立 MQTT 主題的訂閱，並建立該主題的發佈操作。為了示範多種發佈類型，偶數任務使用 QoS 0 （發佈封包傳送後即完成），奇數任務使用 QoS 1 （收到 PUBACK 封包後即完成）。