本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
CoreMQTT 代理连接共享演示
此演示托管在 Amazon-FreeRTOS 存储库中,该存储库已过时。建议您在创建新项目时从此处开始。如果您已经有一个基于现已弃用的 Amazon-FreeRTOS 存储库的现有 FreeRTOS 项目,请参阅亚马逊 FreeRTOS Github 存储库迁移指南。
介绍
CoreMQTT 连接共享演示项目向您展示了如何使用多线程应用程序通过 TLS 与Amazon MQTT 代理建立连接,并在客户端和服务器之间进行双向身份验证。此演示使用基于 mbedTLS 的传输接口实现来建立服务器和经过客户端身份验证的 TLS 连接,并演示了 Q oS 1 级别上的 MQ
要设置和运行 FreeRTOS 演示,请按照中的步骤操作FreeRTOS 入门。
此演示使用线程安全队列来保存与 MQTT API 交互的命令。在此演示中有两个任务需要注意。
-
MQTT 代理(主要)任务处理来自命令队列的命令,而其他任务则将其排队。此任务进入循环,在此期间它处理来自命令队列的命令。如果收到终止命令,则此任务将脱离循环。
-
演示子发布任务创建 MQTT 主题的订阅,然后创建发布操作并将其推送到命令队列。然后,这些发布操作由 MQTT 代理任务运行。demo subpub 任务等待发布完成(以执行命令完成回调表示),然后进入短暂延迟,然后开始下一次发布。此任务显示了应用程序任务将如何使用 CoreMQTT 代理 API 的示例。
对于传入的发布消息,CoreMqtt 代理会调用单个回调函数。该演示还包括一个订阅管理器,该管理器允许任务指定回调,以调用有关他们订阅的主题的传入发布消息。在此演示中,代理的传入发布回调会调用订阅管理器,对任何已注册订阅的任务进行分散发布。
此演示使用带有双向身份验证的 TLS 连接进行连接Amazon。如果在演示期间网络意外断开连接,则客户端会尝试使用指数退避逻辑重新连接。如果客户端成功重新连接,但代理无法恢复之前的会话,则客户端将重新订阅与前一会话相同的主题。
单线程与多线程
CoreMqtt 有两种使用模式,单线程和多线程(多任务)。单线程模型仅使用来自一个线程的 CoreMQTT 库,并要求您在 MQTT 库中重复进行显式调用。相反,多线程用例可以在代理(或守护程序)任务中在后台运行 MQTT 协议,如此处记录的演示所示。当您在代理任务中运行 MQTT 协议时,无需显式管理任何 MQTT 状态或调用MQTT_ProcessLoop
API 函数。此外,当您使用代理任务时,多个应用程序任务可以共享一个 MQTT 连接,而无需诸如互斥锁之类的同步基元。
源代码
演示源文件命名为mqtt_agent_task.c
,可以在
目录和GitHubfreertos
/demos/coreMQTT_Agent/simple_sub_pub_demo.c
功能
此演示至少创建了两个任务:一个是处理 MQTT API 调用请求的主要任务,另一个是创建这些请求的可配置数量的子任务。在此演示中,主要任务创建子任务,调用处理循环,然后进行清理。主要任务创建了与代理的单个 MQTT 连接,该连接在子任务之间共享。子任务向代理创建 MQTT 订阅,然后向其发布消息。每个子任务都使用独特的主题进行发布。
主任务
主应用程序任务 RunCoreMQTTAgentDemo
命令
当您调用 CoreMQTT 代理 API 时,它会创建一个发送到代理任务队列的命令,该命令将在中进行处理MQTTAgent_CommandLoop()
。在创建命令时,可以传递可选的完成回调和上下文参数。相应的命令完成后,将使用传递的上下文和作为命令结果创建的任何返回值调用完成回调。完成回调的签名如下所示:
typedef void (* MQTTAgentCommandCallback_t )( void * pCmdCallbackContext, MQTTAgentReturnInfo_t * pReturnInfo );
命令完成上下文是用户定义的;在本演示中,它是:struct MQTTAgentCommandContext
在以下情况下,命令被视为已完成:
-
在 QoS > 0 时订阅、取消订阅和发布:收到相应的确认数据包后。
-
所有其他操作:调用相应的 CoreMQtt API 后。
在命令完成之前,命令使用的任何结构,包括发布信息、订阅信息和完成上下文,都必须保持在作用域内。在调用完成回调之前,调用任务不得重复使用命令的任何结构。请注意,由于完成回调由 MQTT 代理调用,因此它将使用代理任务的线程上下文而不是创建命令的任务运行。诸如任务通知或队列之类的进程间通信机制可用于发出命令完成的调用任务信号。
运行命令循环
命令在中连续处理MQTTAgent_CommandLoop()
。如果没有要处理的命令,则循环将等待最多一个命令添加到队列中;如果没有添加任何命令,它将运行一次迭代MQTT_ProcessLoop()
。MQTT_AGENT_MAX_EVENT_QUEUE_WAIT_TIME
这样可以确保管理 MQTT Keep-Alive,并确保即使队列中没有命令,也能收到任何传入的发布。
命令循环函数将返回的原因如下:
-
除此之外,命令还会返回任何状态码
MQTTSuccess
。错误状态由命令循环返回,因此您可以决定如何处理。在此演示中,重新建立 TCP 连接,并尝试重新连接。如果出现任何错误,则可以在后台进行重新连接,而无需使用 MQTT 的其他任务进行任何干预。 -
已处理断开连接命令(来自
MQTTAgent_Disconnect
)。命令循环退出以便 TCP 可以断开连接。 -
终止命令(来自
MQTTAgent_Terminate
)已处理。此命令还将任何仍在队列中或等待确认数据包的命令标记为错误,返回代码为MQTTRecvFailed
。
订阅管理器
由于演示使用多个主题,订阅管理器是将订阅的主题与独特的回调或任务关联起来的便捷方式。此演示中的订阅管理器是单线程的,因此不应同时由多个任务使用。在此演示中,订阅管理器函数只能从传递给 MQTT 代理的回调函数中调用,并且只能在代理任务的线程上下文中运行。
简单的订阅-发布任务
的每个实例都会 prvSimpleSubscribePublishTask