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進行檢查ui

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

       mosquitto程序啓動時將建立訂閱樹,該過程將建立三個節點:訂閱樹總根節點、業務子樹根節點和系統子樹根節點,這兩個子樹根節點做爲訂閱樹總根節點的兩個子節點,其中訂閱樹總根節點和業務子樹的根節點中topic成員的值爲空字符串,而系統子樹根節點中保存的值爲「$SYS」,如圖:                  spa

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

 

搭建訂閱樹    
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中)server

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

能夠看到,在上面都使用了_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
就被轉換爲以下鏈表結構:
                                     
相關文章
相關標籤/搜索