在这篇文章中,我们将讨论 MQTT 的Keep Alive功能以及为什么该功能对移动网络特别重要。
MQTT 基于传输控制协议 (TCP)
。该协议确保数据包以“可靠、有序和错误检查”的
方式在 Internet 上传输。然而,通信双方之间的传输有时会不同步。例如,如果其中一方崩溃或有传输错误。在 TCP 中,这种不完全连接的状态称为半开连接
。要记住的重要一点是,通信的一侧继续运行,并且不会通知另一侧的故障。仍然连接的一方继续尝试发送消息并等待确认。
正如 Andy Stanford-Clark(MQTT 协议的发明者)所指出的,移动网络中半开放连接的问题越来越多:
“虽然 TCP/IP 理论上会在套接字中断时通知您,但在实践中,特别是在移动和卫星链接等事物上,它们通常通过空中“假” TCP 并在每一端重新放置标头,但 TCP 很有可能会话到“黑洞”,即它看起来仍然打开,但实际上只是将你写给它的任何东西都扔到地板上。”
Andy Stanford-Clark 关于“为什么需要保持活动?”的主题 资源
MQTT 包含一个保持活动功能,它为半开连接问题提供了一种解决方法(或者至少可以评估连接是否仍然打开)。
保持活动状态确保代理和客户端之间的连接仍然打开,并且代理和客户端知道已连接。当客户端与代理建立连接时,客户端会以秒为单位将时间间隔传送给代理。此时间间隔定义了代理和客户端不能相互通信的最长时间。
MQTT 规范说明如下:
“Keep Alive ...是客户端完成传输一个控制数据包的点和它开始发送下一个控制包的点之间允许经过的最大时间间隔。客户端有责任确保间隔发送的控制包之间的间隔不超过保持活动的值。在没有发送任何其他控制包的情况下,客户端必须发送一个 PINGREQ 包。
只要消息交换频繁,并且不超过keep-alive间隔,就不需要额外发送消息来建立连接是否仍然打开。
如果客户端在保持活动期间没有发送消息,它必须向代理发送一个 PINGREQ 数据包以确认它可用,并确保代理也仍然可用。
代理必须在保持活动间隔的一倍半内断开未发送消息或 PINGREQ 数据包的客户端。同样,如果客户端在合理的时间内没有收到代理的响应,它应该关闭连接。
让我们仔细看看 keep alive 消息。保持活动功能使用两个数据包:
PINGREQ
PINGREQ 由客户端发送,并向代理指示客户端仍处于活动状态。如果客户端不发送任何其他类型的数据包(例如,PUBLISH 或 SUBSCRIBE 数据包),则客户端必须向代理发送 PINGREQ 数据包。客户端可以随时发送 PINGREQ 数据包以确认网络连接仍然存在。PINGREQ 数据包不包含有效负载。
PINGRESP
当代理收到 PINGREQ 数据包时,代理必须回复 PINGRESP 数据包以向客户端显示它仍然可用。PINGRESP 数据包也不包含有效负载。
如果代理没有收到来自客户端的 PINGREQ 或任何其他数据包,则代理关闭连接并发送最后的遗嘱和遗嘱消息
(如果客户端指定了 LWT)。
设置适当的保持活动值是MQTT 客户端
的责任。例如,客户端可以将保活间隔调整为其当前信号强度。
最长存活时间为 18 小时 12 分 15 秒。
如果保活间隔为 0,则保活机制被停用。
通常,断开连接的客户端会尝试重新连接。有时,代理仍然有客户端的半开连接。当发生半开连接并且 MQTT 代理仍将其视为在线的客户端时,它会重新连接并执行client take-over
. 然后,代理关闭与同一客户端的先前连接(由客户端标识符确定),并与客户端建立新连接。此行为可确保半开连接不会阻止断开连接的客户端重新建立连接。