一、基本概念

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}.