原文:www.hivemq.com/blog/mqtt-e…
本篇文章在翻译过程中,对相关内容进行了一些删减,比如文字超链接
作者:HiveMQ Team
发布时间:July 17, 2019
更新于:2023年6月6日
欢迎来到MQTT基础课程的第三部分,基础课程共分10部,涵盖MQTT协议的核心特性,概念,优势。本篇文章将讨论MQTT客户端概念,MQTT代理服务器概念,及客户端和代理服务器之间如何建立连接。
在基础课程系列的第二部分,我们讨论了“发布/订阅”架构,及MQTT协议如何使用这个架构模型去进行收发消息, 现在快速回顾一下这些核心概念:
- “发布/订阅”模型解耦了发布者与订阅者之间的消息传递,即消息的发送和接收互不感知
- MQTT协议使用消息主题来分发消息到特定的订阅者M。 主题是用一个具有可层级化的字符串表示,并且可以被用来过滤和路由消息
现在,让我们深入MQTT的世界,全面了解一下MQTT代理服务器,并且学习一些MQTT代理服务器连接的基础概念。
MQTT客户端和MQTT代理服务器概述
MQTT协议的两个主要组件分别为:客户端 和 代理服务器。MQTT客户端可以是任何设备,只要在设备上能运行MQTT协议库且能成功连接MQTT代理服务器就可以。“发布者”和“订阅者”这两个标签用来表示客户端是发送消息方还是订阅接收消息方。MQTT代理服务器能响应所有接收到的消息,并且可以过滤和转发这些消息至已订阅了这些消息的客户端。MQTT代理服务也可以处理客户端身份验证和授权,并管理所有带持久化特性的会话数据,让我们深入研究基本的MQTT组件。
MQTT客户端是什么?
在IoT中, 一个MQTT client 会涉及到发布者和订阅者。发布者就是可以发送消息的客户端,订阅者就是可以接收消息的客户端。因此MQTT客户端既可以是发布者,也可以是订阅者。
MQTT客户端可以是任何设备,从微型控制器到大的服务器,只要能运行MQTT协议库并且通过网络能连接到MQTT代理服务器就可以
MQTT client library 可以是一个软件模块,也可以是一个实现了MQTT协议的包,只要能提供接口给应用或者设备正常使用MQTT协议就可以。这些库使得向应用程序或设备添加MQTT协议变得更加容易,而无需从头实现协议。
MQTT客户端的库可以是多平台,多语言化的,例如,Android, Arduino, C, C++, C#, Go, iOS, Java, JavaScript, .NET等等。你可以在MQTT wiki中找到自己要用的客户端库。
MQTT客户端可以用普通的计算机,只要能运行带图形化的MQTT客户端进行测试就可以。能使用TCP/IP网络协议并且安装了具有MQTT协议功能的软件设备,都可以叫MQTT客户端。MQTT是基于TCP/IP协议之上设计的,因此任何能使用TCP/IP通信并且实现了MQTT协议的设备都可以称为MQTT客户端。MQTT协议的客户端实现简单明了,非常适合小型设备。
MQTT代理服务器是什么?
MQTT代理服务器在“发布/订阅”系统中就是一个中心枢纽,能从发布者那里接收消息,也可分发消息到订阅者。在MQTT客户端之间MQTT代理服务器扮演者着非常重要通信角色,它能保证消息的可靠传输。
MQTT代理服务器会包含以下功能:
- 处理大量的并发连接: 根据实现的不同,代理服务器可以处理数百万并发连接的MQTT客户端。它通过弥合不同设备、网络和软件系统之间的差距,实现了它们之间的通信。
- 过滤和路由消息: 代理服务器可以根据订阅主题过滤消息,并确定哪些客户端应该接收该消息。
- 会话管理: 代理服务器维护所有已连接且要求持久化会话的客户端数据,包括订阅和包括订阅和未发送的消息。
- 认证和授权: 代理服务器负责根据客户端提供的凭据对客户端进行身份验证和授权。代理服务器是可扩展的,有利于自定义身份验证、授权和与后端系统的集成。除了身份验证和授权之外,代理服务器还可以提供其他安全特性,例如对传输中的消息进行加密和访问控制列表。
- 可伸缩性、集成和监控: MQTT代理服务器必须具有可伸缩性,以便处理大量消息和客户端,可集成到后端系统中,易于监视,并且具有抗故障能力。为了满足这些需求,MQTT代理服务器必须使用最先进的事件驱动的网络处理、开放的扩展系统和标准的监视提供程序。代理服务器还可以提供用于管理和监视 MQTT系统的高级特性,例如消息过滤、消息持久性和实时分析。
此外,一些MQTT代理服务器还支持集群,集群允许代理服务器有多个实例协同工作,以处理大量客户端和消息。
HiveMQ满足MQTT代理服务器的所有这些需求,而且还提供了一个健壮的可伸缩性的消息传递系统
现在我们已经讨论了MQTT代理服务器和它的职责,让我们接下来看一下MQTT客户端是如何和MQTT代理服务器建立连接的。
如何在MQTT客户端和MQTT代理服务器之间建立通信?
MQTT协议的关键特性是它在物联网设备之间能高效且轻量级的传递消息。这种通信的基础是MQTT连接,它使设备能够安全可靠地与MQTT代理服务器交换数据。在本节中,我们将探索建立MQTT连接和所涉及的不同参数。通过了解MQTT连接的工作原理,可以优化物联网部署,以获得更好的性能、安全性和可伸缩性。
MQTT协议基于TCP/IP,这意味着客户端和代理服务器必须有一个TCP/IP协议栈。
MQTT连接是存在于一个客户端和一个代理服务器之间的行为,客户端从不直接连接到其他客户端。为了启动连接,客户端向代理服务器发送CONNECT消息,代理服务器用CONNACK消息和一个状态代码进行响应。一旦连接建立,代理服务器将其保持打开状态,直到客户端发送断开连接命令或连接中断。
本节将探讨通过NAT建立MQTT连接,以及MQTT客户端如何通过向代理服务器发送CONNECT消息来启动连接。我们将深入研究MQTT CONNECT消息的细节,并将重点放在一些基本选项上,包括ClientId、 Clean Session、 Username/Password、 Will Message 和 Keep Alive。此外,我们将讨论代理对CONNECT消息的响应,该消息是包含两个数据项的CONNACK消息: 会话当前标志和连接返回代码。
通过NAT创建MQTT连接
大多数情况下,MQTT客户端在路由器之后,路由器能够使用NAT将私有网络地址(如192.168.x.x 或10.0.x.x)转换为面向公众的地址。如前所述,MQTT客户端通过向代理服务器发送CONNECT消息来启动连接。由于代理服务器有一个公共地址并保持连接开放以支持消息的双向发送和接收(在初始化CONNECT之后) ,位于NAT路由器后面的MQTT客户端将不会遇到任何困难。
对于那些不知情的人来说,NAT是一种常见的网络技术,路由器使用它来允许私有网络上的设备通过一个公共IP地址访问互联网。NAT的工作原理是将私有网络上设备的IP地址转换为路由器的公共IP地址,反之亦然。
对于MQTT,NAT路由器后面的客户端仍然可以与MQTT代理服务器通信,因为代理服务器具有公共IP地址,所以可以通过NAT与客户机端进行连接。但是,NAT可能会出现一些潜在的问题,例如配置端口转发或打开防火墙端口以允许传入的流量到达MQTT代理服务器。此外,一些NAT实现可能对可以建立的并发连接的数量有限制,这可能会影响MQTT系统的可伸缩性。
现在,我们了解了NAT后面的MQTT客户端如何与代理服务器建立连接,让我们进一步了解MQTT CONNECT 消息及其内容。
MQTT客户端如何使用CONNECT 消息进行连接?
现在让我们检查一下 MQTT CONNECT 命令消息,客户端将其发送给代理服务器启动连接。如果此消息格式不正确,或者从打开网络套接直到发送CONNECT消息之间过了太长时间,代理服务器将终止连接,以阻止恶意客户端使代理服务器速度变慢。除了MQTT 3.1.1规范中指定的其他详细信息之外,比较好的MQTT客户端还会发送以下内容。
让我们关注一些重要的选项:
虽然MQTT库的使用者可能会发现CONNECT消息中的某些信息很有用,但是某些细节可能与库的实现者更相关。要完全理解消息中包含的所有信息,请参考 MQTT 3.1.1规范。
让我们看看MQTT CONNECT数据包元素,比如 ClientId、 Clean Session、 Username/Password、 Will Message、 Keep Alive 等。
MQTT CONNECT数据包中的ClientId是什么?
ClientId 是一个唯一标识符,用于区分连接到代理服务器的每个MQTT客户端,并使代理服务器能够跟踪客户端的当前状态。为了确保唯一性,ClientId应该指定到每个客户端和代理服务器。如果代理服务器不需要维护状态,MQTT 3.1.1允许使用空的ClientId。但是,此连接必须将clean会话标志设置为 true,否则代理服务器将拒绝该连接。
MQTT CONNECT数据包中的CleanSession是什么?
CleanSession标志能够标识客户端是否希望与代理服务器建立持久会话。当CleanSession设置为 false (CleanSession = false)(被认为是一个持久会话)时,代理服务器会存储客户端的所有订阅消息以及客户端错过的所有消息(服务质量(qoS)等级1或2)( www.hivemq.com/blog/mqtt-e… CleanSession 设置为 true (CleanSession = true)时,代理服务器不为客户端保留任何信息,并从任何持久化会话中丢弃任何以前的状态。
MQTT CONNECT数据包中的用户名/密码是什么?
MQTT提供了客户端身份验证和授权的用户名和密码选项。但是,需要注意的是,以纯文本形式发送此信息会带来安全风险。为了降低这种风险,我们强烈建议使用加密或哈希(比如通过 TLS)来保护凭据。我们还建议在传输敏感数据时使用安全传输层。
另外,一些代理服务器(如 HiveMQ)提供SSL证书身份验证,完全不需要用户名和密码凭证。采取这些预防措施可以确保MQTT通信保持安全并防止潜在的安全威胁。
MQTT CONNECT数据包中的Will Message是什么?
MQTT 的Last Will and Testament(LWT)特性会包含一条遗嘱消息,当客户端意外断开连接时,该消息会通知其他客户端。客户端可以在CONNECT消息中将此消息指定为MQTT消息和主题。当客户端突然断开连接时,代理服务器代表客户端发送LWT消息。在本系列的第9部分了解有关 MQTT 最后遗嘱和遗嘱的更多信息。
MQTT CONNECT数据包中的Keep Alive是什么?
MQTT keep alive特性允许客户端以秒为单位指定时间间隔,并在建立连接时将其传递给代理服务器。这个时间间隔表示代理服务器和客户端之间不发送消息的最长时间。为了确保连接保持活动状态,客户端发送常规的 PING 请求消息,代理服务器使用 PING 响应进行响应。此方法允许双方确定另一方是否仍然可用。在本系列的第10部分了解有关 MQTT Keep Alive 功能的更多信息。
当从 MQTT 3.1.1客户端连接到 MQTT 代理服务器时,keep alive 间隔是必不可少的。但是,有些 MQTT 库具有其他配置选项,例如队列消息存储在特定实现中的方式。
MQTT 代理服务器的CONNACK消息
当代理服务器收到CONNECT消息时,它会以CONNACK消息回应客户端
CONNACK 消息包含两个数据:
- 会话标识
- 连接状态码
CONNACK 消息中的sessionPresent是什么?
sessionPresent标志可用来通知客户端以前的会话在代理服务器上是否仍然可用。如果客户端请求了一个干净的会话,则标志将始终为 false,表示没有以前的会话。
但是,如果客户端请求恢复前一个会话,并且代理服务器已存储会话信息,这个标志设置为true。此标志帮助客户端确定是否需要重新订阅主题,或者代理服务器是否仍然拥有前一个会话的订阅。
CONNACK 消息中的returnCode标志是什么?
返回码是一个状态代码,它会通知客户端尝试连接的结果是成功还是失败。此码可以表示各种类型的错误,例如无效凭据或不受支持的协议版本。
如下为一组返回码:
Return Code | Return Code Response |
---|---|
0 | Connection accepted |
1 | Connection refused, unacceptable protocol version |
2 | Connection refused, identifier rejected |
3 | Connection refused, server unavailable |
4 | Connection refused, bad user name or password |
5 | Connection refused, not authorized |
关于这些码更详细的解释,参见the MQTT specification.
必须关心连接消息的返回码,因为它可以帮助诊断连接问题。例如,如果返回代码指示身份验证失败,客户端可以尝试使用正确的凭据重新连接。对于连接成功的MQTT来讲,sessionPresent标志和连接returnCode是至关重要的。
如何维护好一个MQTT连接?
如果你想知道在消息没有被发送时如何维护一个连接,或者当一个连接断开了如何诊断,这些都不用担心。我们将在本系列中进一步深入讨论这些主题。
总结
总之,理解 MQTT 客户端和代理服务器的角色以及连接建立过程对于任何有兴趣使用MQTT协议的人来说都是必不可少的。MQTT客户端库使得向应用程序和设备添加MQTT协议变得容易,而无需从头实现协议。MQTT代理服务器负责接收、筛选和向订阅客户端发送消息,并处理客户端身份验证和授权。