嵌入式開發(fā)一直都存在“效率低下”的問題赏淌,很多人疑惑踩寇,也搞不明白到底咋回事?
不矯情六水,我們直接上mqtt的源代碼俺孙。
1辣卒、假設(shè)已經(jīng)順利解決了mqtt的源代碼在Linux上的編譯問題(經(jīng)驗表明該過程從來都不順利,按下不表)睛榄,下面開始mqtt協(xié)議的使用荣茫;
2、首先场靴,尋找到一個demo工程啡莉,看看作者想要我們怎么操作,如下圖:
從代碼中可粗看旨剥,例子中先建立一個context咧欣,然后調(diào)用connect,等待一會再調(diào)用disconnect函數(shù)轨帜,沒有多余流程该押,大概了解只是介紹了如何連接平臺。
竟然這么簡單阵谚,簡直撿到寶了2侠瘛!梢什!是這樣嗎奠蹬??嗡午?
3囤躁、調(diào)用MQTTAsync_create,但是不知道它的各個形參都什么意思荔睹?什么格式狸演?怎么使用?注意什么僻他?繼續(xù)尋找函數(shù)解釋宵距,如下圖:
從這大段英文解釋中,知道了需要傳遞一個指針地址吨拗,網(wǎng)站地址满哪,clientid,持久化類型劝篷,持久化上下文哨鸭,這里網(wǎng)站地址格式具體是啥?持久化類型和上下文是啥娇妓?怎么用像鸡?需要研究mqtt官方協(xié)議文檔才能明白,文檔就不貼了哈恰。里面有提到了persistence函數(shù)和destroy函數(shù)只估,跟這倆什么關(guān)系志群?都得查資料。
里面的MQTTAsync是什么鬼仅乓?看代碼吧
差點一屏沒截完赖舟,里面好多注釋是我加的,結(jié)合代碼分析夸楣,大概了解了這是一個保存某個連接參數(shù)和狀態(tài)等等一些列信息的最外層索引結(jié)構(gòu)宾抓,系統(tǒng)分配保存,只給我們一個指針用豫喧,具體單個變量含義就不說了石洗,具體每個函數(shù)時都會涉及到這些變量的操作。
4紧显、知道了這些參數(shù)的含義是不是就可以上手了讲衫,沒那么簡單,這些指針表示的數(shù)據(jù)孵班,我是malloc一直給系統(tǒng)用涉兽,還是用局部變量調(diào)用完就釋放,這直接決定了會不會內(nèi)存泄漏篙程,也沒人跟我說枷畏,需要翻看這個函數(shù)里面到底是怎么操作我給的數(shù)據(jù)的。進入函數(shù):
不好虱饿,有一個子函數(shù)拥诡,那就得分析為啥搞個子函數(shù)?發(fā)現(xiàn)這個子函數(shù)也提供給了用戶使用氮发,那這倆有啥區(qū)別渴肉?又得從子函數(shù)的參數(shù)意義入手了。搜索發(fā)現(xiàn)該子函數(shù)沒有任何注釋爽冕,而且上一個問題也沒有解決仇祭,那就只能硬著頭皮繼續(xù)了。
5扇售、進入MQTTAsync_createWithOptins里面前塔,看看它到底是怎么使用我給的數(shù)據(jù)的?這決定了我該不該保留數(shù)據(jù)承冰,以什么形式保留數(shù)據(jù)?帶著疑問進入函數(shù):
進入后發(fā)現(xiàn)函數(shù)超大食零,這里只標(biāo)注了一部分數(shù)據(jù)困乒。
為解決疑問1(怎么處理我給的數(shù)據(jù)的),需要依次對該函數(shù)的每個參數(shù)過一遍贰谣,看系統(tǒng)是怎么處理的娜搂,它有沒有保存下來我給的參數(shù)迁霎,發(fā)現(xiàn)MQTTStrdump函數(shù)處理我給的數(shù)據(jù),繼續(xù)進入內(nèi)部發(fā)現(xiàn)它重新申請了內(nèi)存百宇,保存了我的clientid考廉,那明白了我給的參數(shù)就可以用完釋放了,不占用系統(tǒng)空間携御。
(注意:對mqtt庫來說允許釋放昌粤,但到底需不需要保存,需要根據(jù)我如何設(shè)計自動重連功能啄刹,進一步考慮數(shù)據(jù)存放的形式涮坐,最終來決定這里只考慮mqtt函數(shù)限制),同樣方法查找其他參數(shù)誓军。
對問題2袱讹,connect和connectWIthOption到底差異到哪兒?看最后一個參數(shù)的差別昵时,發(fā)現(xiàn)在持久化上捷雕,那繼續(xù)翻看MQTT官方協(xié)議看持久化章節(jié)的規(guī)定,看MQTTPersistence_create函數(shù)內(nèi)部到底怎么處理的持久化壹甥,我需不需要對該數(shù)據(jù)進行保存等等救巷。
最后還需要做決定,對mqtt庫提供的這倆函數(shù)盹廷,到底選擇哪一個征绸,哪個更適合我們的業(yè)務(wù)。繼續(xù)翻看代碼……俄占,終于在崩潰前管怠,我決定用connect函數(shù)。
6缸榄、對這個connect函數(shù)里外翻了一遍后渤弛,我們就開始涉及自己的數(shù)據(jù)結(jié)構(gòu),哪些是需要直接確定隱藏不給用戶看的甚带,哪些是需要用戶傳遞的她肯,這就涉及到產(chǎn)品需求和業(yè)務(wù)邏輯了,需要花時間分析鹰贵,這里省略晴氨;
7、解決了第一個函數(shù)碉输,是不是只有第一個函數(shù)復(fù)雜籽前,其他都是so easy
那再看第二個:
對這個函數(shù),大概意思是注冊callback函數(shù)的,那都有哪些callback函數(shù)枝哄?挨個查他們的定義肄梨,好確定如何操作(過程就省略,不貼圖了)挠锥。
知道了定義众羡,就可以直接用了?不是的蓖租,需要確定這些函數(shù)指針是不是可以傳NULL粱侣,原則上我傳NULL,告訴系統(tǒng)我不想接收回調(diào)數(shù)據(jù)沒毛病啊菜秦,細看發(fā)現(xiàn)允許cl和dc為NULL甜害,不允許ma為空,這都需要我們一行行分析代碼球昨。
再分析發(fā)現(xiàn)尔店,我們必須傳遞消息到來的接收函數(shù)否則系統(tǒng)就不認,天哪主慰,除了看代碼竟然沒人告訴我嚣州,需要這樣操作。
退一步共螺,如果一開始不看這些代碼直接給了NULL该肴,恰好又向demo里那樣沒判斷返回值(這很常見,看第一張圖)藐不,那就等著以后調(diào)試時匀哄,問題頻出焦頭爛額吧,等著測試小姐姐一個一個的bug上報雏蛮,心跳加速吧涎嚼。
8、剩下的其他一大推什么訂閱挑秉,發(fā)布法梯,接收等等函數(shù)就不分析了,就這一個create函數(shù)犀概,保證你1天都搞不明白立哑,上面都省略了函數(shù)查找的過程,省略了分析執(zhí)行邏輯的過程姻灶,省略了挨個字節(jié)分析mqtt協(xié)議的過程铛绰,省略了專業(yè)英文翻譯的過程。
說了一大推产喉,發(fā)現(xiàn)只搞明白了一個最簡單create 的函數(shù)的使用至耻,還有連接若皱,注冊镊叁,發(fā)布接收這些哪個都都比create復(fù)雜的多尘颓。
不就調(diào)用一個函數(shù)嗎?總共寫下來就一行晦譬,不超過50個字母疤苹,怎么那么磨嘰,還一步都不能省敛腌,我要求不高卧土,只是想好好的調(diào)用一個函數(shù)而已,這么費勁招誰惹誰了像樊?
咳咳尤莺,這還是在linux平臺上,還沒考慮每個芯片的特性生棍,芯片的寄存器設(shè)置規(guī)則颤霎,芯片的技術(shù)手冊描述,電路圖的設(shè)計約束涂滴,沒考慮操作系統(tǒng)的限制友酱,沒考慮……
說了這么多,你是不是能稍微理解嵌入式開發(fā)的“低效率”了柔纵,以后把“低效率”換成是“負責(zé)任”缔杉,或許會讓大家更舒服些!