一、基本概念
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) terminated: {shutdown,conflict}.
注意,沖突上線,後者會把前者擠掉,但是前者不會觸發離線函數,僅僅把session毀掉重建而已.
後者正常下線
(2)、cleansession==0的情況
場景1,用戶端自身第一次上線下線
注意,這裡不銷毀session
最終,session會有過期時間,時間到會銷毀,時間(貌似2個小時?)詳見emqttd_session.erl
session(firecat_heartbeat001/firecatGTerm) terminated: {shutdown,expired}.
場景2,用戶端自身第N次(N>1)上線下線
注意,這裡不建立session
最終,session會有過期時間,時間到會銷毀,時間詳見emqttd_session.erl
場景3,用戶端先正常上線,後相同clientid用戶端在别的地方又上線,造成clientid沖突
注意,沖突上線,後者會把前者擠掉,但是前者不會觸發離線函數,session也不毀掉不重建.