Mosquitto --topic


訂閱樹的概念
        Mosquitto通過訂閱樹的方式來管理所有的topic以及客戶端的訂閱關系,它首先將所有的topic按照/分割並組織成一棵樹結構,從根節點到樹中的每個節點即組成該節點所對應的一個topic,每個topic都保存一個訂閱列表,該訂閱列表中保存了所有訂閱當前topic的客戶端信息。例如有如下訂閱關系:
客戶端a1,a2,a3訂閱了topic:A1/B1/C1m
客戶端b1,b2訂閱了topic:A2/B2/C2
客戶端c1,c2訂閱了topic:A1/B1/C3
客戶端d1訂閱了topic:A2/B3

則上述訂閱樹如圖。

 

 

Mosquitto程序在實現中根據topic消息的性質將訂閱樹分為兩顆子樹:業務子樹和系統子樹;mosquitto程序中將topic分為兩種類型來處理:系統topic業務topic,前者主要用於發布和維護mosquitto內部的系統消息,后者的topic是用戶訂閱的業務topic,做這種區分的原因是因為這兩種的類型的topic性質和實現方式上有許多差別,這種差別主要體現在以下3點:

1)生存周期不同,系統topic無論是否有用戶訂閱都會存在與訂閱樹中,而業務topic必須有客戶端訂閱才能存在(除非其消息字段retain設置為1)。

2)創建方式不同,系統topic在消息發布時進行創建,業務topic即可以在訂閱時創建也可以在消息發布時創建(此時需要該消息retain字段設置為1)。

3)消息保存方式不同,凡是發布到系統topic的消息都會被保存下來,業務消息將直接掛到訂閱列表的各context的消息隊列中,如果沒有連接訂閱或未設置其retain字段,消息將不會被保存下來,消息的retain字段是否被設置在函數mqtt3_handle_publish進行檢查

訂閱樹的創建:(在src/database.c中的mqtt3_db_open函數實現)

       mosquitto程序啟動時將創建訂閱樹,該過程將創建三個節點:訂閱樹總根節點、業務子樹根節點和系統子樹根節點,這兩個子樹根節點作為訂閱樹總根節點的兩個子節點,其中訂閱樹總根節點和業務子樹的根節點中topic成員的值為空字符串,而系統子樹根節點中保存的值為“$SYS”,如圖:                  

 訂閱樹采用孩子兄弟鏈表法保存,確切來說應該是說業務子樹和系統子樹都是采用孩子兄弟鏈表法保存,而這兩個節點還是作為總樹根節點的兩個子節點。

 

搭建訂閱樹    
1)
  系統子樹搭建過程  
        Mosquitto中,系統子樹在發布系統消息時,自動檢測topic片段是否存在,如果不存在則在系統topic上創建節點以搭建訂閱樹。搭建過程如下:
將Topic按照“/"分成 topic片段;根據第一個topic片段“$SYS”遍歷訂閱樹的子節點找到系統子樹的根節點;根據topic下一個片段查找系統子樹,若沒有則創建這個節點,依次方案處理直至topic片段解析完。
       所用到的函數調用: mqtt3_db_messages_easy_queue(在src/database.c中)  --->mqtt3_db_messages_queue (在src/subs.c中) --->  _sub_add(在src/subs.c中)

2)業務子樹搭建過程
      分為兩種類型:訂閱時創建和消息發布時創建。后者與系統Topic的方式類似。前者在收到訂閱請求后將該客戶端掛到對應的業務子樹節點的訂閱列表中,若不存在客戶端所訂閱的Topic,則會自動為之添加相應節點。
所用到的函數調用: mqtt3_handle_subscribe(在src/read_handle_server.c中) --->mqtt3_sub_add(在src/subs.c中) --->_sub_add(在src/subs.c中)

可以看到,在上面都使用了_sub_add函數,而調用它的分別是mqtt3_db_messages_queue 和mqtt3_sub_add函數,而且這三個函數都是在src/subs.c中,不妨來看看它們的邏輯。
mqtt3_db_messages_queue:(系統子樹的搭建)

mqtt3_sub_add(業務子樹的搭建)
 
 _sub_add:
 

       這幾張圖把訂閱樹的構建的大致邏輯勾勒出來。可以看見業務子樹和系統子樹的搭建大致邏輯相似,但是在局部處理上還是有區別,最大的區別就是如果創建業務子樹的時候如果有沒有找到topic片段,則會向訂閱樹中添加相應節點,而創建系統子樹時則不會(原因見前面提到的二者的區別的第二點)。
      還有就是這里在根據用戶發布的topic(一個字符串)來在樹結構中查詢,用到了一個技巧,就是調用_sub_topic_tokenise函數將這個字符串分解,並組成一個鏈表的形式,然后通過遍歷這個鏈表逐步完成對樹結構的查詢、添加等工作,最后釋放掉這個鏈表。這里的鏈表就相當於一個緩沖區,值得借鑒。
例如一個Topic: year/month/day
就被轉換為如下鏈表結構:
 



                                     


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM