轉:mosquitto源碼分析(三)

 本文由逍遙子撰寫,轉發請標註原址:算法

http://write.blog.csdn.NET/postedit/21462255數據結構

1、  Mosquito的核心功能分析函數

3.一、訂閱樹post

Mosquitto經過訂閱樹的方式來管理全部的topic以及客戶端的訂閱關係,它首先將全部的topic按照/分割並組織成一棵樹結構,從根節點到樹中的每一個節點即組成該節點所對應的一個topic,每一個topic都保存一個訂閱列表,該訂閱列表中保存了全部訂閱當前topic的客戶端信息。例若有以下訂閱關係:ui

客戶端a1,a2,a3訂閱了topic:A1/B1/C1.net

客戶端b1,b2訂閱了topic:A2/B2/C2blog

客戶端c1,c2訂閱了topic:A1/B1/C3遞歸

客戶端d1訂閱了topic:A2/B3隊列

則在mosquitto程序中須要先將topic按照/進行分割,而後將分割後的topic片斷組織成訂閱樹,上述訂閱樹的示意圖爲圖3-1:字符串

 

圖3-1          訂閱樹示意圖

Mosquitto程序在實現中根據topic消息的性質將訂閱樹分爲兩顆子樹:業務子樹和系統子樹;mosquitto程序中將topic分爲兩種類型來處理:系統topic和業務topic,前者主要用於發佈和維護mosquitto內部的系統消息,後者的topic是用戶訂閱的業務topic,作這種區分的緣由是由於這兩種的類型的topic性質和實現方式上有許多差異,這種差異主要體如今如下4點:

1)生存週期不一樣,系統topic不管是否有用戶訂閱都會存在與訂閱樹中,而業務topic必須有客戶端訂閱才能存在(除非其消息字段retain設置爲1);

2)建立方式不一樣,系統topic在消息發佈時進行建立,業務topic便可以在訂閱時建立也能夠在消息發佈時建立(此時須要該消息retain字段設置爲1);

3)消息保存方式不一樣,凡是發佈到系統topic的消息都會被保存下來,業務消息將直接掛到訂閱列表的各context的消息隊列中,若是沒有鏈接訂閱或未設置其retain字段,消息將不會被保存下來;

消息的retain字段是否被設置在函數mqtt3_handle_publish進行檢查,在該函數中有以下代碼:

retain = (header & 0x01);

該代碼可獲取消息頭部的第一個bit位,在mqtt3.1協議中,該爲用於表示消息的類型是否爲retain。

訂閱樹在程序中的採用孩子—兄弟鏈表法來表示。其主要涉及的數據結構是:

struct _mosquitto_subhier

struct _mosquitto_subleaf

 

 

3.1.一、訂閱樹的搭建

一、建立訂閱樹

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

 

圖3-2          訂閱樹的建立

訂閱樹的建立主要在文件database.c中mqtt3_db_open函數裏實現。訂閱樹中節點的數據結構爲struct _mosquitto_subhier,訂閱樹採用「孩子—兄弟」鏈表法保存。

二、搭建訂閱樹

在訂閱樹中,系統子樹與業務子樹的搭建過程不同,系統子樹是在系統消息發佈時建立,而業務子樹建立過程便可以在消息發佈時建立也能夠在客戶端訂閱時才建立。

1)系統子樹搭建過程

Mosquitto中,系統子樹在發佈系統消息時,自動檢測topic片斷是否存在,若是不存在則在系統topic上建立節點以搭建訂閱樹。例如,mosquitto程序啓動時,將首先向系統topic:$SYS/broker/version發送一條版本消息「mosquittoversion 1.2」,此時訂閱樹的系統子樹只有一個根節點,如圖3.2所示,其搭建過程以下:

(1)將topic按照」/」分紅topic片斷,系統Topic:$SYS/broker/version將被分割爲$SYS、broker、version三部分。

(2)根據第一個topic片斷「$SYS」遍歷訂閱樹的子節點找到系統子樹的根節點。

(3)根據topic下一個片斷「broker」查找系統子樹;此時系統子樹中不存在topic片斷「broker」的節點,則爲訂閱樹產生一個節點,其數據結構爲:struct_mosquitto_subhier。此時訂閱樹由圖3-2變爲圖3-3所示:

 

圖3-3添加broker節點以後的訂閱樹

上述過程在函數mqtt3_db_messages_queue中調用函數_sub_add來完成。

(4)依此處理topic剩下的片斷,在系統子樹中添加topic片斷「version」,該過程經過遞歸調用函數_sub_add來完成。添加完「version」片斷以後的訂閱樹如圖3-4所示。

 

圖3-4添加version以後的訂閱樹

系統子樹搭建過程當中,所用到的函數調用關係以下圖3-5所示

 

圖3-5 系統子樹搭建的函數調用關係

2) 業務子樹搭建過程

業務子樹的搭建分爲兩種類型:一種在訂閱時建立;一種是在消息發佈時建立,這種方式與系統topic的建立過程同樣,所以下面的內容將主要描述前一種方式。

在mosquitto程序運行期間,收到一條客戶端的訂閱請求後將調用函數mqtt3_sub_add將該客戶端掛到對應的業務子樹節點的訂閱列表中,此時,若是所訂閱樹中不存在客戶端所訂閱的topic,則會自動爲之添加相應的節點,此過程即爲訂閱樹的業務子樹搭建過程。例如,在mosquitto程序啓動時(此時訂閱樹如圖3-2所示)客戶端訂閱了topic:year/month/events,業務子樹的搭建過程爲:

(1)將topic按照」/」分紅topic片斷,topic:year/month/event將被分割成:year、month、events三個topic片斷;此過程在函數mqtt3_sub_add中完成。

(2)遍歷訂閱樹的第一級子節點,以查找業務子樹的根節點,找到業務子樹的根節點以後進行後續的處理。此過程在函數mqtt3_sub_add中完成。

(3)依此處理三級topic片斷:year、month、events,此過程與系統topic的添加過程類似,若是訂閱樹中不某個存在topic片斷,則爲訂閱樹添加此節點,添加完成以後的訂閱樹如圖3-6:本條功能在函數_sub_add中完成。

 

圖3-6 添加業務topic以後的訂閱樹

業務子樹搭建過程當中,所用到的函數調用關係以下圖3-7所示

圖3-7 業務子樹搭建的函數調用關係

相關文章
相關標籤/搜索