我的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) 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協議和emqttd開源專案個人理解(1) - Clean Session和Retained Message
我的mqtt協議和emqttd開源專案個人理解(4) - 客戶端CleanSession=0時,上線接收離線訊息,原始碼分析