MQTT心跳机制

简介: MQTT心跳机制

心跳机制


Keep Alive指定连接最大空闲时间T,当客户端检测到连接空闲时间超过T时,必须向Broker发送心跳报文PINGREQ,Broker收到心跳请求后返回心跳响应PINGRESP。若Broker超过1.5T时间没收到心跳请求则断开连接,并且投递遗嘱消息到订阅方;同样,若客户端超过一定时间仍没收到心跳响应PINGRESP则断开连接。


连接空闲时发送心跳报文可以降低网络请求,弱化对带宽的依赖。


Keep Alive设定时机


创建连接时,在CONNECT报文中指定,单位s。


Client Take-Over


场景:客户端与Broker连接正常,然后客户端快速重启(小于1.5T),再重新连接Broker,在未达到1.5T这段时间内,客户端与Broker存在两条连接。

处理措施: 先断开之前的连接再建立新的连接。


一、CONNECT(连接)

当客户端向服务器建议一个TCP/IP端口连接,协议基本会话必须使用一个CONNECT flow建立。


下面是一个较为完整的CONNECT消息结构:

image.png



说明:

1、Fixed header/固定头部:

DUP,QoS和RETAIN标志不能被使用在CONNECT消息中(无效)。


Remaining Length是可变头(12字节)的长度和payload的长度。这可以是一个多字节的字段。


2、Variable header/可变头部(12字节)

byte1~byte9:

协议名称(MQIsdp)和协议版本(v3)都是固定的。

byte10:Connect Flags

一个字节表示,除了第1位是保留未使用,其它7位都具有不同含义。业务上很重要,对消息总体流程影响很大,需要牢记。

bit[1]:Clean Session

0,表示如果订阅的客户机断线了,要保存为其要推送的消息(QoS为1和QoS为2),若其重新连接时,需将这些消息推送(若客户端长时间不连接,需设置一个过期值);


1,断线服务器即清理相关信息,重新连接上来之后,会再次订阅。

bit[2]:Will Flag


定义了客户端(没有主动发送DISCONNECT消息)出现网络异常导致连接中断的情况下,服务器需要做的一些措施。


简而言之,就是客户端预先定义好,在自己异常断开的情况下,所留下的最后遗愿(Last Will),也称之为遗嘱(Testament)。


这个遗嘱就是一个由客户端预先定义好的主题和对应消息,附加在CONNECT的可变头部中,在客户端连接出现异常的情况下,由服务器主动发布此消息。只有在Will Flag位为1     时,Will Qos和Will Retain才会被读取,此时消息体payload中要出现Will Topic和Will Message具体内容,否则,Will QoS和Will Retain值会被忽略掉。


bit[3-4]:Will Qos

若标识了Will Flag值为1,那么Will QoS就会生效,否则会被忽略掉。


两位表示,和PUBLISH消息固定头部的QoS level含义一样。这里先略过,到PUBLISH消息再回过头来看看,会更明白些。


bit[5]:Will RETAIN

如果设置Will Flag值为1,Will Retain就会生效,否则它将被忽略。


当客户端意外断开服务器发布其Will Message之后,服务器是否应该继续保存。这个属性和PUBLISH固定头部的RETAIN标志含义一样,这里先掠过。

bit[6-7]:User name 和 password Flag

用于授权,两者要么为00 , 要么为11,否则都是无效。00--表示客户端可自由连接/订阅;11--表示连接/订阅需要授权。

byte11-12:心跳时间(Keep Alive timer)


以秒为单位,定义服务器端从客户端接收消息的最大时间间隔。一般应用服务会在业务层次检测客户端网络是否连接,不是TCP/IP协议层面的心跳机制(比如    开启SOCKET的SO_KEEPALIVE选项)。 一般来讲,在一个心跳间隔内,客户端发送一个PINGREQ消息到服务器,服务器返回PINGRESP消息,完成一次心跳    交互,继而等待下一轮。若客户端没有收到心跳反馈,会关闭掉TCP/IP端口连接,离线。 16位两个字节,可看做一个无符号的short类型值。最大值,2^16-    1 = 65535秒 = 18小时。


最小值可以为0,表示客户端不断开。一般设为几分钟,比如微信心跳周期为300秒。

   

3、Payload/消息体

消息体定义的消息顺序(如上表所示),约定俗成,不得更改,否则将可能引起混乱。

若Will Flag值为0,那么在payload中,Client Identifer后面就不会存在Will Topic和Will Message内容。

若User Name和Password都为0,意味着Payload/消息体中,找不到User Name和password的值,就算有,也是无效。标志决定着是否读取与否。


Will Message编码

Will Message在CONNECT Payload/消息体中,使用UTF-8编码。假设内容为“abcd”,大概如下:

image.png

注意:PUBLISH的Payload/消息体中以二进制编码保存。


例如:某刻客户端异常关闭触发服务器会PUBLISH此消息。那么服务器会直接把byte3-byte6之间字符取出,保存为二进制,附加到PUBLISH消息体中,大概存储如下:

image.png


二、连接异常中断通知机制


CONNECT消息一旦设置在可变头部设置了Will flag标记,那就启用了Last-Will-And-Testament特性,此特性很赞。也就是说,一旦客户端出现异常中断,     便会触发服务器发布Will Message消息到Will Topic主题上去,通知Will Topic订阅者,对方因异常退出。


三、握手(CONNACK)


接收到CONNECT消息之后,服务器应该返回一个CONNACK消息作为响应:


1、若客户端绕过CONNECT消息直接发送其它类型消息,服务器应关闭此非法连接 若客户端发送CONNECT之后未收到CONNACT,需要关闭当前连接,然后重新连接;


2、相同Client ID客户端已连接到服务器,先前客户端必须断开连接后,服务器才能完成新的客户端CONNECT连接。客户端发送无效非法CONNECT消息,服务器需要关闭


一个完整的CONNACK消息大致如下:

image.png


连接握手返回码:

image.png


只有0-5目前被使用到,其他值有待日后使用。一般返回值为0x00,表示连接建立。非法的请求,需要返回相应的数值。


从上面看出,一个CONNACT,四个字节表示。一个正常的CONNACT消息实际内容可能如下: 0x20 0x02 0x00 0x00


若是在私有协议中,两个字节就足够了。


很多时候,客户端和服务器端在没有消息传递时,会一直保持着连接。虽然不能依靠TCP心跳机制(比如SO_KEEPALIVE选项),业务层面定义心跳机制,会 让连接状态检测、控制更为直观。


四、PINGREQ

由客户端发送到服务器端,证明自己还在一直连接着呢。两个字节,固定值。

客户端会在一个心跳周期内发送一条PINGREQ消息到服务器端。

心跳频率在CONNECT可变头部“Keep Alive timer”中定义时间,单位为秒,无符号16位short表示。

image.png


五、PINGRESP

服务器收到客户端的PINGREQ请求之后,会立即响应一个两个字节固定格式的PINGRESP消息。


服务器一般若在1.5倍的心跳周期内接收不到客户端发送的PINGREQ,可考虑关闭客户端的连接描述符。此时的关闭连接的行为和接收到客户端发送DISCONNECT消息的处理行为一致,但对客户端的订阅不会产生影响(不会清除客户端订阅数据),这个需要牢记。


若客户端发送PINGREQ之后的一个心跳周期内接收不到PINGRESP消息,可考虑关闭TCP/IP套接字连接。


image.png


六、DISCONNECT

客户端主动发送到服务器端,表明即将关闭TCP/IP连接。此时要求服务器要完整、干净的进行断开处理,不能仅仅类似于关闭连接描述符类似草草处理之。 需要两个字节,值固定:

image.png


服务器要根据先前此客户端在发送CONNECT消息可变头部Connect flag中的“Clean session flag”所设置值,再次复习一下:


1、值为0,服务器必须在客户端断开之后继续存储/保持客户端的订阅状态。这些状态包括:

存储订阅的消息QoS1和QoS2消息

正在发送消息期间连接丢失导致发送失败的消息

以便当客户端重新连接时以上消息可以被重新传递。


2、值为1,服务器需要立刻清理连接状态数据。

有一点需要牢记,服务器在接收到客户端发送的DISCONNECT消息之后,需要主动关闭TCP/IP连接。

相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
|
5月前
|
消息中间件 网络安全 开发工具
消息队列 MQ产品使用合集之使用grpc proxy,生产者心跳并没有发送至Default中,如何解决
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
5月前
|
消息中间件 Serverless 网络性能优化
消息队列 MQ产品使用合集之客户端和服务器之间的保活心跳检测间隔是怎么设置的
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
6月前
MQTT的心跳保活机制是通过`setKeepAliveInterval()`方法设置的
MQTT的心跳保活机制是通过`setKeepAliveInterval()`方法设置的
978 2
|
6月前
MQTT协议本身是支持心跳保活机制的
MQTT协议本身是支持心跳保活机制的
647 3
|
6月前
MQTT的心跳保活机制是通过`setKeepAliveInterval()`方法设置的,
MQTT的心跳保活机制是通过`setKeepAliveInterval()`方法设置的,
567 1
|
26天前
|
消息中间件 JSON Java
开发者如何使用轻量消息队列MNS
【10月更文挑战第19天】开发者如何使用轻量消息队列MNS
66 5
|
20天前
|
消息中间件 存储 Kafka
MQ 消息队列核心原理,12 条最全面总结!
本文总结了消息队列的12个核心原理,涵盖消息顺序性、ACK机制、持久化及高可用性等内容。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
|
24天前
|
消息中间件
解决方案 | 云消息队列RabbitMQ实践获奖名单公布!
云消息队列RabbitMQ实践获奖名单公布!
|
1月前
|
消息中间件 安全 Java
云消息队列RabbitMQ实践解决方案评测
一文带你详细了解云消息队列RabbitMQ实践的解决方案优与劣
67 6
|
1月前
|
消息中间件 存储 弹性计算
云消息队列RabbitMQ实践
云消息队列RabbitMQ实践