MQTT 客户端和代理以及 MQTT 服务器连接建立说明 - MQTT 要点:第 3 部分
- HiveMQ现在是开源的。HiveMQ 社区版实现了 MQTT 代理规范,兼容 MQTT 3.1、3.1.1 和 MQTT 5。HiveMQ MQTT 客户端是一个基于 Java 的 MQTT 客户端实现,与 MQTT 3.1.1 和 MQTT 5 兼容。这两个项目都可以在GitHub上的Apache开源许可证下获得。
上节,我们解释了发布/订阅模式的工作原理以及如何在 MQTT 中应用它。
以下是核心概念的快速回顾:
- 发布/订阅将发送消息的客户端(发布者)与接收消息的客户端(订阅者)分离。
- MQTT 使用消息的主题(主题)来确定哪个消息发送到哪个客户端(订阅者)。主题是一个分层结构的字符串,可用于过滤和路由消息(更多详细信息)。
我们的上一篇文章为您提供了发布/订阅模型的高级视图,以及它与传统消息队列的区别。这篇文章采用了一种实用的方法,并充满了有关 MQTT 的基本知识:术语 MQTT 客户端和代理的定义、MQTT 连接的基础知识、带有其参数的连接消息,以及通过代理确认建立连接。
MQTT 客户端和 MQTT 代理简介
由于 MQTT 将发布者与订阅者分离,因此客户端连接始终由代理处理。在我们进入这些连接的细节之前,让我们清楚客户和经纪人(client/broker)的含义。
Client 客户
当我们谈论客户端时,我们几乎总是指的是 MQTT客户端 。发布者和订阅者都是 MQTT 客户端。发布者和订阅者标签是指客户端当前是发布消息还是订阅接收消息(发布和订阅功能也可以在同一 MQTT 客户端中实现)。
MQTT 客户端是运行 MQTT 库并通过网络连接到 MQTT 代理的任何设备(从微控制器到成熟的服务器)。例如,MQTT 客户端可以是一个非常小的、资源受限的设备,它通过无线网络连接并具有最低限度的库。
MQTT 客户机也可以是运行图形化 MQTT 客户机以进行测试的典型计算机。基本上,任何通过 TCP/IP 堆栈使用 MQTT 的设备都可以称为 MQTT 客户端。MQTT 协议的客户端实现非常简单和简化。易于实施是MQTT非常适合小型设备的原因之一。MQTT 客户端库可用于多种编程语言。例如,Android,Arduino,C,C++,C#,Go,iOS,Java,JavaScript和.NET。您可以在 MQTT wiki 上查看完整列表。
Broker 代理
MQTT 客户端的对应项是 MQTT 代理。代理是任何发布/订阅协议的核心。根据实现,代理可以处理多达数百万个并发连接的 MQTT 客户端。
代理负责接收所有消息、过滤消息、确定订阅每条消息的人员以及将消息发送到这些订阅的客户端。代理还保存具有持久会话的所有客户端的会话数据,包括订阅和错过的消息)。代理的另一个职责是客户端的身份验证和授权。通常,代理是可扩展的,这有助于自定义身份验证、授权和集成到后端系统中。集成尤其重要,因为代理通常是直接暴露在 Internet 上的组件,处理大量客户端,并且需要将消息传递到下游分析和处理系统。 正如在上一篇文章中所讨论的,订阅所有消息并不是一个真正的选择。简而言之,代理是每条消息必须通过的中心枢纽。
MQTT 连接
MQTT 协议基于 TCP/IP。客户端和代理都需要有一个 TCP/IP 堆栈。
MQTT 连接始终位于一个客户端和代理之间。客户端从不直接相互连接。要启动连接,客户端向代理发送 CONNECT 消息。代理使用 CONNACK 消息和状态代码进行响应。建立连接后,代理将使其保持打开状态,直到客户端发送断开连接命令或连接中断。
通过 NAT 的 MQTT 连接
在许多常见用例中,MQTT 客户端位于路由器后面,该路由器使用网络地址转换 (NAT) 从专用网络地址(如 192.168.x.x、10.0.x.x)转换为面向公众的地址。正如我们已经提到的,MQTT 客户端通过向代理发送 CONNECT 消息来启动连接。由于代理具有公共地址并保持连接打开以允许双向发送和接收消息(在初始连接之后),因此位于 NAT 后面的客户端完全没有问题。
客户端启动与连接消息的连接
现在让我们看一下 MQTT CONNECT 命令消息。要启动连接,客户端向代理发送命令消息。如果此 CONNECT 消息格式不正确(根据 MQTT 规范),或者在打开网络套接字和发送连接消息之间经过了太多时间,则代理将关闭连接。此行为可阻止可能降低代理速度的恶意客户端。一个善意的 MQTT 3 客户端发送一条连接消息,其中包含以下内容(除其他外):
CONNECT 消息中包含的某些信息对于 MQTT 库的实现者来说可能比对该库的用户更感兴趣。有关所有详细信息,请查看 MQTT 3.1.1 规范 。
我们将重点关注以下选项:
- ClientId 客户端标识
客户机标识符 (ClientId) 标识连接到 MQTT 代理的每个 MQTT 客户机。代理使用 ClientId 来标识客户端和客户端的当前状态。因此,此 ID 对于每个客户端和代理应该是唯一的。在 MQTT 3.1.1 中,如果您不需要代理保存状态,则可以发送空的 ClientId。空的 ClientId 会导致没有任何状态的连接。在这种情况下,必须将干净会话标志设置为 true,否则代理将拒绝连接。
- Clean Session 清除会话
干净会话标志告诉代理客户端是否要建立持久会话。在持久会话 (CleanSession = false) 中,代理存储客户端的所有订阅以及订阅了服务质量 (QoS) 级别 1 或 2 的客户端的所有丢失消息。如果会话不是持久性的 (CleanSession = true),那么代理不会为客户机存储任何内容,而是清除任何先前持久会话中的所有信息。
- Username/Password 用户名/密码
MQTT 可以发送用户名和密码进行客户端身份验证和授权。但是,如果此信息未加密或哈希处理(通过实现或 TLS),则密码将以纯文本形式发送。我们强烈建议使用用户名和密码以及安全传输。
- Will Message 遗嘱留言
最后遗嘱消息是 MQTT 的最后遗嘱和遗嘱 (LWT) 功能的一部分。当客户端不正常断开连接时,此消息会通知其他客户端。当客户端连接时,它可以以 MQTT 消息的形式为代理提供最后遗嘱,并在 CONNECT 消息中提供主题。如果客户端不正常断开连接,代理将代表客户端发送 LWT 消息。您可以在本系列的第 9 部分中了解有关 MQTT 最后遗嘱的更多信息。
- Keep Alive 保持活力
保持活动状态是客户端指定的时间间隔(以秒为单位),并在建立连接时与代理通信。此间隔定义了代理和客户端在不发送消息的情况下可以忍受的最长时间。客户端承诺定期向代理发送 PING 请求消息。代理使用 PING 响应进行响应。此方法允许双方确定另一方是否仍然可用。有关 MQTT 保持活动功能的详细信息,请参阅本系列的第 10 部分。
基本上,这就是从 MQTT 3.1.1 客户端连接到 MQTT 代理所需的所有信息。单个库通常具有可以配置的其他选项。例如,排队消息在特定实现中的存储方式。
带有 CONNACK 消息的代理响应
当代理收到 CONNECT 消息时,它有义务使用 CONNACK 消息进行响应。
CONNACK 消息包含两个数据条目:
- The session present flag 会话显示标志
会话存在标志告诉客户端代理是否已经具有从与客户端的先前交互中可用的持久会话。当客户端连接时,干净会话设置为 true 时,会话存在标志始终为 false,因为没有可用的会话。如果客户端连接时将“干净会话”设置为 false,则有两种可能性:会话信息是否可用于 clientId。并且代理已经存储了会话信息,会话存在标志为真。否则,如果代理没有 clientId 的任何会话信息,则会话存在标志为 false。MQTT 3.1.1 中添加了此标志,以帮助客户端确定是否需要订阅主题,或者主题是否仍存储在持久会话中。
- A connect return code 连接返回代码
CONNACK 消息中的第二个标志是连接确认标志。此标志包含一个返回代码,告知客户端连接尝试是否成功。
返回代码一览:
有关每个代码的更详细说明,请参阅 MQTT 规范( MQTT specification) 。
Loose ends 有始有终
您可能想知道 MQTT 如何在没有发送消息的情况下保持连接打开,或者您如何知道连接何时丢失。别担心,稍后我们将用一整期的必需品系列来讨论这些主题。
我们的 MQTT 要点系列的第三部分到此结束。我们希望您至少学到了一件关于 MQTT 的新知识。查看我们下一篇关于在 MQTT 中发布、订阅和取消订阅的文章。
分到此结束。我们希望您至少学到了一件关于 MQTT 的新知识。查看我们下一篇关于在 MQTT 中发布、订阅和取消订阅的文章。