现在,我们将介绍用于保持连接的控制报文:PINGREQ 和 PINGRESP。

除了用于连接、发布和订阅的控制报文外,MQTT 还有一种用于模拟客户端和服务器之间的心跳以保持连接的报文类型。它们是 PINGREQ 和 PINGRESP 报文,我们通常称之为心跳报文。
客户端会周期性地向服务器发送 PINGREQ 报文,让服务器知道连接是正常的并且客户端仍然处于活动状态。对于每个收到的 PINGREQ 报文,服务器会回复一个 PINGRESP 报文,这样客户端也可以知道连接是正常的并且服务器仍然处于活动状态。

我们使用 MQTTX CLI 来建立一个客户端连接到公共 MQTT 服务器。我们没有发布消息或订阅主题,但在 Wireshark 中,我们仍然可以看到客户端和服务器之间定期出现 MQTT 数据包。这些数据包是 PINGREQ 和 PINGRESP。

也可以使用命令将创建一个客户端连接,Keep Alive 为 5 秒,这将使我们能够尽快看到客户端发送 PINGREQ 消息。


我们会发现 PINGREQ 和 PINGRESP 数据包总是只有 2 字节大小,并且它们的内容似乎从不改变:

这两种数据结构报文也特别简单。

PINGREQ & PINGRESP
数据包结构
PINGREQ 和 PINGRESP 包之间的唯一区别在于固定头部中的包类型字段。PINGREQ 的包类型是 12(0x0C),而 PINGRESP 的包类型是 13(0x0D)。
PINGREQ 和 PINGRESP 包之后跟随的保留长度字段的值总是 0,因为 无论 PINGREQ nor PINGRESP 包中都不包含可变头或负载。

这种结构使得 PINGREQ 和 PINGRESP 包的大小最小化,因此发送它们不会占用太多带宽。

常见问题
A:keepalive 参数的值是一个表示秒数的整数。例如, keepalive=300 表示客户端应当每 300 秒向 MQTT 代理发送一条消息,例如 PUBLISH。在另外 150 秒后,代理会关闭连接。Keep Alive 间隔的最大值为 65535,即 18 小时 12 分钟 15 秒。
A:您可以将 MQTT Keep Alive 机制禁用,如果将间隔设为 0: keepalive=0 。
A:默认值因您使用的 MQTT 客户端库而异。例如,Python MQTT 客户端将默认 Keep Alive 间隔设为 60 秒。同样,Eclipse Paho MQTT 浏览器基于的 JavaScript 客户端库也是如此。而 Arduino 的 MQTT PubSubClient keepalive 间隔默认设为 15 秒。
A:客户端在建立连接时会在 MQTT 协议中确定 Keep Alive 间隔。
对于 MQTT v.5.0 客户端,还有一种从代理服务器到客户端设置 MQTT Keep Alive 值的反向方式。代理服务器可以告诉客户端它应该使用的 Keep Alive 间隔。 max_keepalive 选项允许客户端使用不大于指定值的 Keep Alive 间隔。但对于 MQTT v.3.1 和 v.3.1.1 客户端,却没有这样的机制来指定使用什么 Keep Alive 间隔。

PINGREQ 和 PINGRESP 是 MQTT 中最简单的包,它们的内容是固定的。我们唯一可以改变的是通过连接时的保持活动选项来影响客户端发送 PINGREQ 包的频率。
下两个图就是使用Wirshark捕获的数据包具体截图:


如果服务器在 1.5 倍的心跳保留时间内没有收到客户端的任何控制包,它将认为客户端是不活跃的或网络异常并断开连接。在本文的包示例中,连接时我们将心跳保留设置为 5 秒,因此服务器的超时时间为 7.5 秒。
对于客户端,如果在发送 PINGREQ 包后的一段时间内没有收到服务器返回的 PINGRESP 包,它应该断开连接。这个时间长度主要取决于客户端对网络延迟的预期以及每个客户端 SDK 的具体实现。
参考链接: