我的mqtt协议和emqttd开源项目个人理解(25) - 协议里面Clean Session为0和1的区别

本文详细解析了MQTT协议中的会话管理机制,包括Session的概念、生命周期及CleanSession标记的作用。通过对比CleanSession为0和1时的场景,阐述了其在不同情况下的应用,如会话重用、消息持久化等。并分析了EMQ源码中hook流程,揭示了客户端上线、下线和冲突登录时的不同处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、基本概念

Session 会话

定义

  • 定义:某个客户端(由ClientID作为标识)和某个服务器之间的逻辑层面的通信
  • 生命周期(存在时间):会话 >= 网络连接

CleanSession 标记
在Connect时,由客户端设置 
0 —— 开启会话重用机制。网络断开重连后,恢复之前的Session信息。需要客户端和服务器有相关Session持久化机制。
1 —— 关闭会话重用机制。每次Connect都是一个新Session,会话仅持续和网络连接同样长的时间。


客户端 Session
已经发送给服务端,但是还没有完成确认的 QoS 1 和 QoS 2 级别的消息 
已从服务端接收,但是还没有完成确认的 QoS 2 级别的消息


服务器端 Session
会话是否存在,即使会话状态的其它部分都是空  (SessionFlag)
客户端的订阅信息  (ClientSubcription)
已经发送给客户端,但是还没有完成确认的 QoS 1 和 QoS 2 级别的消息
即将传输给客户端的 QoS 1 和 QoS 2 级别的消息
已从客户端接收,但是还没有完成确认的 QoS 2 级别的消息
(可选)准备发送给客户端的 QoS 0 级别的消息
 

二、关于协议的问答

问:问个mqtt协议的问题,cleansession为什么要区别0和1,他们各自的用途和应用场景是什么?

答:为 1 的时候,服务器每次session 都要重新建立,这也是大多数的场景使用情况;

为 0 的时候可以复用历史的session, 服务端session 是有状态的,可以记录很多信息。

为 0的时候就可以保留 session 了,这个保留的session 是有用的,如果服务端实现了的话,像历史没发出去的消息等等,鉴权信息,等等,可以接着使用。你可以类比我们登陆网页的那个session,没过期的话,可以不用登陆了。

说白了,想接收离线消息,就必须使用cleansession=0,这个就是=0的应用场景:

不管clean session的值是什么,当终端设备离线时,QoS=0,1,2的消息一律接收不到。
当clean session的值为1,当终端设备离线再上线时,离线期间发来QoS=0,1,2的消息一律接收不到。
当clean session的值为0,当终端设备离线再上线时,离线期间发来QoS=0,1,2的消息仍然可以接收到。如果同个主题发了多条就接收多条,一条不差,照单全收。
 

三、emq源码里面,hook上下线流程

1、emq v2当服务器进程重启之后,session会清除掉,没有实现本地持久化。

2、cleansession为0和1的时候,hook里面的上下线,0和1流程大不相同。相同clientid冲突登录。

以下的打印信息来自hook插件源码文件
emqttd:hook('client.connected', fun ?MODULE:on_client_connected/3, [Env]),
emqttd:hook('client.disconnected', fun ?MODULE:on_client_disconnected/3, [Env]),
emqttd:hook('session.created', fun ?MODULE:on_session_created/3, [Env]),
emqttd:hook('session.terminated', fun ?MODULE:on_session_terminated/4, [Env]),

(1)、cleansession==1的情况
场景1,客户端自身上线下线
正常上线
session(firecat_heartbeat001/firecatGTerm) created.
client firecat_heartbeat001 connected, connack: 0
正常下线
client firecat_heartbeat001 disconnected, reason: normal
session(firecat_heartbeat001/firecatGTerm) terminated: normal.

场景2,客户端先正常上线,后相同clientid客户端在别的地方又上线,造成clientid冲突
先正常上线
session(firecat_heartbeat001/firecatGTerm) created.
client firecat_heartbeat001 connected, connack: 0
后冲突上线
session(firecat_heartbeat001/firecatGTerm) terminated: {shutdown,conflict}.
session(firecat_heartbeat001/firecatGTerm) created.
client firecat_heartbeat001 connected, connack: 0
注意,冲突上线,后者会把前者挤掉,但是前者不会触发离线函数,仅仅把session毁掉重建而已.
后者正常下线
client firecat_heartbeat001 disconnected, reason: normal
session(firecat_heartbeat001/firecatGTerm) terminated: normal.


(2)、cleansession==0的情况
场景1,客户端自身第一次上线下线
正常上线
session(firecat_heartbeat001/firecatGTerm) created.
client firecat_heartbeat001 connected, connack: 0
正常下线
client firecat_heartbeat001 disconnected, reason: normal
注意,这里不销毁session
最终,session会有过期时间,时间到会销毁,时间(貌似2个小时?)详见emqttd_session.erl
session(firecat_heartbeat001/firecatGTerm) terminated: {shutdown,expired}.

场景2,客户端自身第N次(N>1)上线下线
正常上线
注意,这里不创建session
client firecat_heartbeat001 connected, connack: 0
正常下线
client firecat_heartbeat001 disconnected, reason: normal
注意,这里不销毁session
最终,session会有过期时间,时间到会销毁,时间详见emqttd_session.erl
session(firecat_heartbeat001/firecatGTerm) terminated: {shutdown,expired}.

场景3,客户端先正常上线,后相同clientid客户端在别的地方又上线,造成clientid冲突
先正常上线
session(firecat_heartbeat001/firecatGTerm) created.
client firecat_heartbeat001 connected, connack: 0
后冲突上线
client firecat_heartbeat001 connected, connack: 0
注意,冲突上线,后者会把前者挤掉,但是前者不会触发离线函数,session也不毁掉不重建.
后者正常下线
client firecat_heartbeat001 disconnected, reason: normal
注意,这里不销毁session
最终,session会有过期时间,时间到会销毁,时间详见emqttd_session.erl
session(firecat_heartbeat001/firecatGTerm) terminated: {shutdown,expired}.
 

 

---

相关阅读:

MQTT协议通俗讲解

我的mqtt协议和emqttd开源项目个人理解(1) - Clean Session和Retained Message

我的mqtt协议和emqttd开源项目个人理解(4) - 客户端CleanSession=0时,上线接收离线消息,源码分析

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值