天天看點

我的mqtt協定和emqttd開源項目個人了解(25) - 協定裡面Clean Session為0和1的差別

一、基本概念

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也不毀掉不重建.

繼續閱讀