当谈到 MQTT 5 时,其中一个最令人激动且具有革命性意义的特性是能够在 MQTT 头部中包含自定义键值属性。这个特性可能会从根本上改变许多 MQTT 部署的方式。与其他协议,例如 HTTP,类似,MQTT 客户端和代理现在可以添加无限数量的自定义或预定义头部来携带元数据。这些元数据具有很大的灵活性,可以根据特定的应用数据进行定制。而预定义的头部主要用于执行许多新的 MQTT 功能。
此外,在 MQTT 数据包中现在包含了原因代码,它们用于表示协议错误的具体情况。这些原因代码通常出现在确认数据包上,它们有助于解释错误情况,并有可能帮助客户端和代理制定补救措施。这些原因代码的范围广泛,从"配额已超出"到"协议错误"等各种情况。客户端和代理需要一起解码和理解这些新增的原因代码,从而丰富了 MQTT 的整体体验。
当我们谈论自定义键值属性和原因代码时,现在让我们来探讨 MQTT 如何处理不支持的功能以及如何使用 CONNACK 返回代码来做出响应。
如何使用 MQTT 5 中的预定义头部来响应不支持的功能?
随着 MQTT 的普及,各种公司提供了各种 MQTT 软件、库或系统。然而,由于不完全遵循 MQTT 规范,某些功能可能无法完全实现,例如 QoS 2、保留消息或持久会话。为了解决这些问题,MQTT 5 引入了一个巧妙的解决方案。它允许那些功能不完整的软件、库或系统(通常在 SaaS 提供中很常见)告知代理它们无法支持某些功能。然后,客户端有责任确保不使用这些不受支持的功能。代理在响应客户端的 CONNECT 数据包时,通过 CONNACK 数据包中的预定义头部来传达对特定功能的不支持。这些头部还可以通知客户端它们无权使用某些功能。
在 MQTT 5 中,可以使用以下预定义头部来指示未实现功能或未经授权的客户端使用:
- 预定义头部 Retain Available:是否可用于保留消息?
- 预定义头部 Maximum QoS:允许客户端发布消息或订阅主题的最大 QoS
- 预定义头部 Wildcard Available:是否可以使用通配符进行主题订阅?
- 预定义头部 Subscription identifiers available:MQTT 客户端是否可用订阅标识符
- 预定义头部 Shared Subscriptions available:MQTT 客户端是否可用共享订阅
- 预定义头部 Maximum Message Size:定义 MQTT 客户端可使用的最大消息大小
- 预定义头部 Server Keep Alive:服务器支持的个别客户端的保活间隔
这些返回代码代表了表达各个 MQTT 客户端权限的重要方法。然而,这一新功能带来了某种平衡:MQTT 客户端必须独立实现对这些代码的解释,并确保应用程序开发人员避免使用代理不支持或客户端没有权限使用的功能。对于那些想要维护严格规范 MQTT 部署的人来说,HiveMQ 完全符合 MQTT 5 的所有功能,从而确保这些自定义头部只会在管理员的决策下用于设置部署中的权限。
增强的会话管理:从清除会话到 MQTT 5 中的“清除启动”
在 MQTT 3.1.1 中,"清除会话"是一个显著的特性,但在 MQTT v5 中已经被"清除启动"所取代。在 MQTT 3.1.1 中,客户端使用"清除会话"功能,根据连接到代理时是否有临时连接或未订阅消息。在连接到代理后,客户端需要发送一个 CONNECT 数据包,其中包括清除会话标志,它可以启用或禁用。如果启用该标志,它表示向代理发出请求,在底层 TCP 连接断开或客户端决定与代理断开连接时,应丢弃所有客户端数据。此外,如果代理有关联到客户端标识符的先前会话,则清除会话 CONNECT 数据包将迫使代理丢弃先前的数据。
MQTT 5 引入了清除启动选项,由 CONNECT 消息中的清除启动标志表示。通过这一标志,代理会放弃任何先前的会话数据,从而启动新的会话。但是,当 TCP 连接在客户端与服务器之间关闭时,会话并不会自动清除。为了在断开连接后触发会话删除,必须将新的头部字段"会话过期间隔"设置为 0。这种修改的清除启动功能增强并简化了 MQTT 的会话处理,相对于之前的"清除会话"/"持久会话"概念,提供了更多的灵活性和更容易的实施。在 MQTT 5 中,会话会保留,除非将"会话过期间隔"设置为 0。会话的删除要么在间隔超时后发生,要么在客户端使用清除启动重新连接时发生。
MQTT 5 中的 AUTH 数据包是什么?
在一个令人激动的发展中,MQTT 5 引入了一种新的数据包类型:AUTH 数据包。这个数据包在实施非传统身份验证机制方面至关重要,我们预计它将在生产环境中发挥关键作用。我们将在另一篇文章中详细讨论其确切语义。
需要理解的关键是,这种新型数据包可以在建立连接后由代理和客户端分发。它允许使用复杂的挑战/响应身份验证方法,例如在 SASL 框架中概述的 SCRAM 或 Kerberos,同时也与先进的 IoT 身份验证方法(如 OAuth)兼容。重要的是,AUTH 数据包使得 MQTT 客户端可以在不需要终止连接的情况下重新进行身份验证。
MQTT 5 如何利用 UTF-8 字符串对增强通信?
为了容纳自定义头部,MQTT 引入了一种新的数据类型,即 UTF-8 字符串对。简而言之,字符串对是一种键-值结构,其中键和值都是字符串数据类型。目前,这种数据类型主要用于自定义头部。
这个新增的数据类型扩展了 MQTT 在传输中使用的数据类型的范围,总共包括七种:
- 位
- 两字节整数
- 四字节整数
- UTF-8 编码字符串
- 可变字节整数
- 二进制数据
- UTF-8 字符串对
对于大多数应用程序用户来说,二进制数据和 UTF-8 编码字符串仍然是 MQTT 库 API 中的首选数据类型。然而,随着 MQTT 5 的引入,预计 UTF-8 字符串对将会更频繁地使用。虽然用户可能不会直接看到其他数据类型,但它们在 MQTT 客户端库和代理中用于构建有效的 MQTT 数据包。
MQTT 5 如何通过双向 DISCONNECT 数据包简化通信?
在 MQTT 3.1.1 中,客户端可以在关闭底层 TCP 连接之前发送一个 DISCONNECT 数据包,以优雅地终止连接。然而,在 MQTT 代理通知客户端需要关闭 TCP 连接的情况下,这个版本存在一个问题。这个问题在新的协议版本中得到了解决。
在增强版 MQTT 中,代理被授权在断开套接字连接之前传输 DISCONNECT 数据包。这一规定使客户端能够理解断开连接的原因,并相应地制定适当的响应。虽然代理没有义务披露确切的原因(例如,出于安全原因),但这个功能有助于开发人员,因为它提供了有关代理终止连接的原因的有价值的信息。
另一个有价值的补充是 DISCONNECT 数据包现在可以携带原因代码,从而简化了揭示断开连接原因的过程,例如在权限无效的情况下。
在 MQTT 5 中对 QoS 1 和 2 进行了改进:取消了对健康连接的消息重传
MQTT 使用持久的 TCP 连接(或具有相同保证的类似协议)进行底层传输。强大的 TCP 连接确保了双向连接,以确保所有客户端或代理发送的 MQTT 数据包都将在另一端接收,并且只接收一次并按顺序发送。这意味着客户端或代理发送的所有 MQTT 数据包都将在另一端接收。在消息在传输过程中断开连接时,QoS 1 和 2 确保消息通过多个 TCP 连接传递。
在 MQTT 3.1.1 协议下,即使 TCP 连接正常,也允许重新传输 MQTT 消息。在实际中,这常常是有害的,可能会导致已经负载繁重的 MQTT 客户端超载。考虑这样的情况:一个 MQTT 客户端需要 11 秒来处理从代理接收的消息,并在处理后发送确认数据包。如果代理在 10 秒超时后重新传输消息,实际上并没有什么好处。这种方法只会消耗宝贵的带宽,并进一步加重 MQTT 客户端的负担。
随着 MQTT 5 的出现,对于健康的 TCP 连接,无论是代理还是客户端,都不允许重新传输 MQTT 消息。
然而,当 TCP 连接断开时,代理和客户端必须重新发送未被确认的数据包。因此,对于 QoS 1 和 2,在 MQTT 5 中仍然具有相同的重要性,就像在 MQTT 3.1.1 中一样。
如果您的用例依赖于重新传输数据包(例如,如果您的实现在某些情况下未能确认数据包),我们建议在升级到 MQTT v5 之前重新评估这种策略。
MQTT 5 如何简化身份验证?
在 MQTT 3.1.1 协议中,当 MQTT 客户端在 CONNECT 数据包中使用密码时,需要提供用户名。这对于某些不需要用户名的用例可能不太方便,例如使用 OAuth 进行身份验证和授权的情况,其中关键信息包含在密码字段中。在 MQTT 5 中,该协议引入了更精细的处理令牌的方式,例如通过 AUTH 数据包。但是,仍然可以在不提供用户名的情况下使用 CONNECT 数据包的密码字段。这个调整提供了一种更简化和直接的身份验证方法,特定情况下非常方便。
总结
虽然 MQTT 协议的核心保持相对不变,但在表面下进行了微妙的改进,为这一广泛采用的 IoT 协议的第 5 版奠定了基础。对于使用 MQTT 库的用户来说,这些修改可能似乎很小,不会从根本上改变 MQTT 的使用方式。然而,对于在 MQTT 库和代理上工作的开发人员来说,这些变化,特别是与协议细节相关的变化,都是关键的,并需要关注。
您必须登录才能发表评论。