MQTT 会话

算法流星
• 阅读 1466

什么是会话?

我们将从客户端向服务端发起 MQTT 连接请求开始,到连接中断直到会话过期为止的消息收发序列称之为会话。因此,会话可能仅持续一个网络连接,也可能跨越多个网络连接存在,如果客户端能在会话过期之前重新建立了连接的话。

在 MQTT v5 中会话过期时间由 Session Expiry Interval 字段决定,早前版本的协议没有限制会话过期时间,但通常由 MQTT 服务端决定。

什么是会话状态?

MQTT 要求客户端与服务端在会话有效期内存储一系列与客户端标识相关联的状态,称之为会话状态。

客户端需要存储以下会话状态:

  • 已发送给服务端,但是还没有完成确认的 QoS 1 与 QoS 2 消息。
  • 从服务端收到的,但是还没有完成确认的 QoS 2 消息。

服务端需要存储以下会话状态:

  • 会话是否存在,即使会话状态其余部分为空。
  • 客户端订阅信息,包括任何订阅标识符。
  • 已发送给客户端,但是还没有完成确认的 QoS 1 与 QoS 2 消息。
  • 等待传输给客户端的 QoS 0 消息(可选),QoS 1 与 QoS 2 消息。
  • 从客户端收到的,但是还没有完成确认的 QoS 2 消息,遗嘱消息和遗嘱延时间隔。
  • 会话过期时间。

会话状态的使用

如果客户端因为网络波动等原因导致连接短暂中断,但在会话过期前重新与服务端建立了连接,那么就可以沿用上次连接建立的订阅关系,不需要重新订阅一遍。在低带宽、不稳定的网络场景下,网络中断可能会发生得很频繁,保存会话状态的方式避免了每次连接都需要重新订阅,降低了重连时客户端和服务端的资源消耗。服务端在客户端脱机期间为其保留未完成确认的以及后续到达的消息,客户端重新连接时再一并转发,既可以避免消息丢失,也能够降低某些场景下用户对网络变化的感知度。

会话的开始与结束

MQTT v5.0 与 v3.1.1 在会话上有着较为显著的变化。MQTT v3.1.1 只有一个 Clean Session 字段,由客户端在连接时指定,为 1 表示客户端和服务器必须丢弃任何先前的会话并创建一个新的会话,且这个会话的生命周期与网络连接保持一致;为 0 则表示服务端必须使用与 Client ID 关联的会话来恢复与客户端的通信(除非会话不存在),客户端和服务器在断开连接后必须存储会话的状态。

MQTT v3.1.1 没有规定持久会话应该在什么时候过期,如果仅从协议层面理解的话,这个持久会话应该永久存在。但在实际场景中这并不现实,因为它会非常占用服务端的资源,所以服务端通常不会遵循协议来实现,而是向用户提供一个全局配置来限制会话过期时间。

而到了 MQTT 5.0,这个问题得到了妥善的解决,Clean Session 字段被拆分成了 Clean Start 字段与 Session Expiry Interval 字段。Clean Start 字段指定是否需要全新的会话,Session Expiry Interval 字段指定会话过期时间,它们在连接时指定,但 Session Expiry Interval 字段可以在客户端断开连接时被更新。因此我们可以很轻易地实现客户端网络连接异常断开时会话被保留,客户端正常下线时会话则随着连接关闭而终结的功能。

客户端如何知道这是被恢复的会话?

显而易见的是,当客户端以期望从先前建立的会话恢复状态的方式发起连接,它需要知道服务端是否存在相应的会话,才能决定在连接建立后是否需要重复一遍订阅操作。关于这一点,MQTT 协议从 v3.1.1 开始,就为 CONNACK 报文设计了 Session Present 字段,用于表示当前连接使用的是否是一个全新会话,客户端可以根据这个字段的值进行判断。

使用建议

开发者需要特别注意 ClientID 与会话之间的联系,如果某些场景下同一个 ClientID 会被不同的应用或者用户多次使用,即每次连接都会有完全不同的行为,那么就需要确保每次连接时都请求了全新的会话。合理地评估是否需要持久会话,如非必要可以在正常离线时将会话设置为立即过期减少服务端资源占用。设置合适的会话过期时间,设置过短,可能会失去存储会话状态的意义,设置过长,可能会过多地占用服务端资源。

版权声明: 本文为 EMQ 原创,转载请注明出处。

原文链接:https://www.emqx.io/cn/blog/m...

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Easter79 Easter79
4年前
tmux快捷键
Tmux快捷键&速查表启动新会话:tmuxnews会话名n窗口名恢复会话:tmuxatt会话名列出所有会话:tmuxls关闭会话:tmuxkillsessiont会话名关闭所有会话:tmuxl
Stella981 Stella981
4年前
Shiro配置cookie以及共享Session和Session失效问题
首先我们看Shiro的会话管理器的配置<!shiro会话管理<!即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的<beanid"sessionManager"class"org.apache.s
Wesley13 Wesley13
4年前
JavaWeb面试篇(7)
61,JDBC访问数据库的基本步骤是什么?1,加载驱动2,通过DriverManager对象获取连接对象Connection3,通过连接对象获取会话4,通过会话进行数据的增删改查,封装对象5,关闭资源62,说说preparedStatement和Statement的区别1,效率:预编译会话比普通会话对象
Wesley13 Wesley13
4年前
Java Web:session
会话:HttpSessionsessionrequest.getSession();//判断是否为新会话session.isNew();//获取一个已经存在的会话HttpSessionsessionrequest.getSession(false);if(session
Stella981 Stella981
4年前
Django组件——cookie与session
Django组件——cookie与session<fontcolor00bff一、会话跟踪技术</font<fontcolorff7f501、什么是会话跟踪技术</font先了解一下什么是会话。可以把
Stella981 Stella981
4年前
Linux应急响应(一):SSH暴力破解
0x00前言SSH是目前较可靠,专为远程登录会话和其他网络服务提供安全性的协议,主要用于给远程登录会话数据进行加密,保证数据传输的安全。SSH口令长度太短或者复杂度不够,如仅包含数字,或仅包含字母等,容易被攻击者破解,一旦被攻击者获取,可用来直接登录系统,控制服务器所有权限。0x01应急场景某天,网站
Stella981 Stella981
4年前
PostgreSQL 动态更新 C 语言函数
PostgreSQL对于C语言编写的函数(包括其他与C语言兼容的语言,如C、Rust等),是动态装载的,用CREATEFUNCTION创建完函数后,并不会立即装载,而是有连接建立之后,客户端第一次调用时才会进行装载,而且是装入到会话进程的内存里面去了。这时候,就算我们把.so文件删除,如果会话之前已调过一次函数的话,客户端还是
Stella981 Stella981
4年前
Django组件——Cookie与session相关
一,会话跟踪技术1什么是会话跟踪技术我们需要先了解一下什么是会话!可以把会话理解为客户端与服务器之间的一次会晤,在一次会晤中可能会包含多次请求和响应。例如你给10086打个电话,你就是客户端,而10086服务人员就是服务器了。从双方接通电话那一刻起,会话就开始了,到某一方挂断电话表示会话结束。在通话过程中,你会向10086发出多个请求,那
程序员小五 程序员小五
2年前
获取会话唯一id
融云RTC服务使用“sessionID”标识一次音视频会话,下文将介绍获取sessionID参数的方式:1.RTCLib获取方式当房间创建后(等同于有第一个人加入)就可以获取RCRTCEnginesharedInstance.room.sessionI