物聯網網關開發:基於MQTT消息總線的設計過程(上)
一、前言
在上一篇中,我們聊了在一個嵌入式系統中,如何利用MQTT消息總線在各進程之間進行通信,文章鏈接:《我最喜歡的進程之間通信方式-消息總線 》。
這樣的通信模型,我之前已經在多個項目中應用過,對於非工控產品來說,通信速度完全足夠。我以前做過測試,在x86平台和ARM平台,一條數據從本地到雲端繞一下,然后再回到本地,可以控制在毫秒級別。
上篇文章只是簡單的介紹了這樣的一種設計思路,並沒有詳細的討論其中的一些細節問題。這一次,我們就來具體的聊一聊物聯網系統中的網關內部程序應該如何設計。
閱讀這篇文章,你可以有如下收獲:
- 物聯網系統中,設備之間是如何通信的;
- 網關中的進程之間消息總線通信模型;
- 網關內部消息總線上的數據如何與服務器進行通信;
- 作為消遣,了解一下物聯網系統中的一些基本知識;
二、網關的作用
物聯網這個詞語的范疇太廣,似乎所有的硬件設備,只要能夠接入網絡,就可以稱之為物聯網產品,似乎物聯網這個詞可以把一切都納入到其中。這么空洞的詞語不利於我們的講解,因此我們就用一個可以感知、想象的場景來代替,那就是智能家居系統,這是最能代表物聯網時代的典型產品了。
2.1 指令轉發
在一個智能家居系統中,假設有這么幾個設備:
這些設備的通信模塊,如果是 WiFi 或者是藍牙,那么一般都可以直接通過手機來控制(當然,需要廠家提供相應的手機 APP),手機就相當於一個中心節點,控制着所有的設備。目前市面上的一些智能設備單品都是這樣的通信方式,例如:空調、吸塵器、空氣凈化器、冰箱等等。只要在這些設備中加一個無線通信模塊即可(例如:ESP8266模塊)。
如果通信模塊是其它的通信模塊,例如:RF433、ZigBee、ZWave等,由於手機沒有這些通信模塊,因此就需要一個網關來“轉發”指令。手機和網關都連接到家中的路由器,處於同一個局域網中,手機把控制指令發送給網關,網關再把指令轉發給相應的設備。通信模型如下:
2.2 外網通信
在上面的通信模型中,手機和網關由於處於同一個局域網中,因此可以直接通信。如果手機不在局域網中呢?那么就要通過雲端的服務器來轉發了,通信模型如下:
- 手機把指令發到服務器;
- 服務器把指令轉發給網關;
- 網關把指令發給指定的設備;
以上描述的是控制指令的流程,如果是設備發出的報警信息呢,數據的流向就是倒過來進行的。
可以看出,網關是所有設備之間通信的中心節點,也是內網與外網之間通信的中轉節點,也就是把各種智能設備連接到互聯網的中轉器。
2.3 協議轉換
上面已經提到,硬件設備上的通信模塊都是確定的(RF,ZigBee,ZWave等等),一般來說,可以把這些通信模塊稱呼為無線通信協議。在一套智能家居系統中,所有設備的無線通信協議大部分都是相同的。
那么,不同類型的無線通信協議設備是否可以共存在同一個系統中呢?
答案是:可以。只要在網關中,集成了相應的無線通信協議模塊就可以達到這個目的!如下圖所示:
從手機APP上看,所有的設備都是相同的,不會關心設備的無線通信協議是什么,因此,發出的控制指令都是協議無關的。
當網關接收到控制指令時,首先根據指令內容查找出目標設備,然后確定目標設備的無線通信協議,最后把指令發送給對應的硬件通信模塊,由該通信模塊通過無線電信號把控制指令發送到設備。
從這個指令的傳輸過程來看,網關就充當着協議轉換的角色。
另外還有一種通信場景:當系統中的一個“輸入”設備與一個“輸出”設備進行綁定/關聯時,例如:
- 紅外感應器與聲光報警器綁定:當紅外感應器監測到人體時,發出信號,然后控制聲光報警器發出報警;
- 門磁與燈綁定:當開門時,門磁發出信號,自動打開燈光;
如果“輸入”設備與“輸出”設備是不同類型的無線通信協議,也需要網關來進行協議轉換。
2.4 設備管理
在一個智能家居系統中,設備可多可少,對這些設備進行管理也是很重要的事情。網關作為系統的中心節點,對設備進行管理的重任理所當然就由網關來承擔。
設備管理功能包括:
設備的添加和刪除;
設備狀態的管理(電量、設備斷網、失聯等等);
設備樹的管理;
2.5 邊沿計算(自動化控制)
在正常的情況下,網關是可以通過路由器,與服務器保持着長連接的。如果服務器的處理能力比較強大,智能家居系統中所有需要處理的事情都可以丟給服務器來計算、處理,服務器在計算之后把處理結果再發送給網關。看起來想法很完美!
但是,考慮下面這 2 種情況:
- 路由器出現問題了,網關無法連接到服務器,因此就無法把本地數據及時上報;
- 系統中出現了異常情況,需要緊急處理,如果把信息上報到服務器,由服務器計算之后再回傳給網關,耗費的時間可能超過了可容忍時間,該如何處理?(可以用車聯網系統來腦補一下這個場景:自動駕駛中的汽車遇到緊急情況,如果把所有信息上傳給服務器,然后等待服務器的下一步指令?)
對於上面的這些場景,把一些計算、處理操作放在網關這一端來處理也許更合適!這也是近幾年比較流行的邊沿計算。
1. 邊緣計算,是指在靠近物或數據源頭的一側,采用網絡、計算、存儲、應用核心能力為一體的開放平台,就近提供最近端服務。
2. 其應用程序在邊緣側發起,產生更快的網絡服務響應,滿足行業在實時業務、應用智能、安全與隱私保護等方面的基本需求。
3. 邊緣計算處於物理實體和工業連接之間,或處於物理實體的頂端。而雲端計算,仍然可以訪問邊緣計算的歷史數據
三、網關內部進程之間的通信
在設計一個應用程序的架構時,可以通過多線程來實現,也可以通過</font color=orange>多進程來實現,每個人的習慣都不一樣,各有各的好處。我們這里不去討論孰優孰劣,因為我對多進程這樣的設計思想比較偏愛,所以就直接按照多進程的程序架構來討論。
3.1 網關中需要哪些進程
網關中需要執行的所有進程,是根據網關的功能來決定的,假設包括如下的功能:
(1)連接外網的進程 Proc_Bridge
網關需要連接到雲端的服務器,需要一個進程與服務器之間保持長連接,這樣就可以及時接收到服務器發來的控制指令,以及把系統內部數據及時上報給服務器。
這個進程需要把從服務器接收到的指令轉發到網關系統內部,把從系統內部接收到的信息轉發給服務器,類似於橋接的功能,因此命名為 Proc_Bridge。
(2)設備管理進程 Proc_DevMgr
這個進程用來執行設備管理功能,設備的添加(入網)、刪除(退網),都由此進程來管理。
(3)協議轉換進程 Proc_Protocol
下行:把應用層的統一通信協議,轉換成不同類型無線通信協議,發送給相應的無線模塊。
上行:把設備上報的、不同類型的無線通信協議,轉換成應用層的統一通信協議。
(4)邊沿計算進程(自動化控制) Proc_Auto
很明顯,這需要一個獨立的進程來處理各種計算,這個進程就相當於系統的大腦。
(5)無線通信協議相關的進程 Proc_ZigBee, Proc_RF, Proc_ZWave
在硬件上,每一種無線通信模塊通過串口或其他硬件連接方式與到網關的 CPU 進行通信,因此,每一種無線通信模塊都需要一個相應的進程來處理。
(6)其他“軟設備”進程 Proc_Xxx
在之前的項目中,還遇到一些硬件設備,它們與門磁、插座等設備在邏輯上處於同一個層次,但是與網關之間是通過 TCP 來連接。對於這樣的設備,也可以使用一個獨立的進程來進行管理。
上面的這些進程,在網關中的運行模型如下:
3.2 MQTT消息總線
以上這些進程之間需要相互通信,不是簡單的點對點通信,而是一個網狀的通信模型。比如:
- 設備管理進程 Proc_DevMgr:當任何一種設備被添加到系統中時,都需要處進行處理,因此它需要與 Proc_ZigBee, Proc_RF, Proc_ZWave 這些進程進行通信;
- 當某個設備上報數據時(例如:Proc_ZigBee),Proc_Protocol 進程需要把數據進行協議轉換,然后 Proc_Bridge 進程把轉換后的數據上報給服務器,同時 Proc_Auto 進程需要檢查這個設備上報的數據是否觸發了其他相關聯的設備;
也就是說,這些進程中間的通信是相互交叉的,如果通過傳統的 IPC 方式(共享內存、命名管道、消息隊列、Socket)等,處理起來比較復雜。
引入了 MQTT 消息總線之后,每個進程只需要掛載到總線上。每個進程只需要監聽自己感興趣的 topic,就可以接收到相應的數據。
既然這些進程之間的通信關系比較復雜,那么一個良好的 topic 設計規范就顯得很重要了!
3.3 Topic 的設計
MQTT 的通信模型是基於訂閱/發布的模式,一個客戶端(進程)接入到消息總線之后,需要注冊自己感興趣的 主題 topic,其他客戶端(進程)往這個 topic 發送消息,即可被訂閱者接收到。
主題 topic 是一個以反斜線(/)分割的字符串,用來表示多層的分級結構,例如下面的這 2 個 topic,是亞馬遜 AWS 平台中在線升級(OTA)相關的 topic:
- $aws/things/MyThing/jobs/get/accepted
- $aws/things/MyThing/jobs/get/rejected
在我們的示例場景中,可以按照下面這樣來設計主題 topic:
(1) Proc_DevMgr
訂閱主題:
iot/v1/ZigBee/Registeriot/v1/ZigBee/Register iot/v1/ZigBee/UnRegister
iot/v1/RF/Registeriot/v1/RF/Register iot/v1/RF/UnRegister
iot/v1/ZWave/Registeriot/v1/ZWave/Register iot/v1/ZWave/UnRegister
(2) Proc_Bridge
訂閱主題:
$iot/v1/Device/Report
發出數據的主題:
iot/v1/Device/Controliot/v1/Device/Control iot/v1/Device/Remove
iot/v1/Auto/AddRuleiot/v1/Auto/AddRule iot/v1/Auto/RemoveRule
(3) Proc_Protocol
訂閱主題:
iot/v1/Device/Controliot/v1/Device/Control iot/v1/Device/Remove
iot/v1/ZigBee/Reportiot/v1/ZigBee/Report iot/v1/RF/Report
$iot/v1/ZWave/Report
發送數據主題:
iot/v1/Device/Reportiot/v1/Device/Report iot/v1/ZigBee/Control
iot/v1/ZigBee/Removeiot/v1/ZigBee/Remove iot/v1/RF/Control
iot/v1/RF/Removeiot/v1/RF/Remove iot/v1/ZWave/Control
$iot/v1/ZWave/Remove
(4) Proc_Auto
訂閱主題:
iot/v1/Auto/AddRuleiot/v1/Auto/AddRule iot/v1/Auto/RemoveRule
$iot/v1/Device/Report
發送數據主題:
$iot/v1/Device/Control
(5) Proc_ZigBee
訂閱主題:
iot/v1/ZigBee/Controliot/v1/ZigBee/Control iot/v1/ZigBee/Remove
發送數據主題:
iot/v1/ZigBee/Registeriot/v1/ZigBee/Register iot/v1/ZigBee/UnRegister
$iot/v1/ZigBee/Report
(6) Proc_RF
訂閱主題:
iot/v1/RF/Controliot/v1/RF/Control iot/v1/RF/Remove
發送數據主題:
iot/v1/RF/Registeriot/v1/RF/Register iot/v1/RF/UnRegister
$iot/v1/RF/Report
(7) Proc_ZWave
訂閱主題:
iot/v1/ZWave/Controliot/v1/ZWave/Control iot/v1/ZWave/Remove
發送數據主題:
iot/v1/ZWave/Registeriot/v1/ZWave/Register iot/v1/ZWave/UnRegister
$iot/v1/ZWave/Report
以上這些主題 topic 的設計,還是有些粗略的。如果借助通配符(#, +, $),可以設計出更靈活的層次結構。
- 多層通配符: “#”是用於匹配主題中任意層級的通配符,多層通配符表示它的父級和任意數量的子層級。
- 單層通配符:“+”加號是只能用於單個主題層級匹配的通配符,在主題過濾器的任意層級都可以使用單層通配符,包括第一個和最后一個層級。
- 通配符:“$”表示匹配一個字符,只要不是放在主題的最開頭,其它情況下都表示匹配一個字符。
我們以一個控制指令為例,來梳理一下數據是如何通過 topic 進行流動:
- Proc_Bridge 進程從服務器接收到控制指令后,發送到消息總線上的 topic: $iot/v1/Device/Control。
- 由於 Proc_Protocol 進程訂閱了這個 topic,所以立刻接收到指令。
- Proc_Protocol 分析指令內容,發現是一個 ZigBee 設備,於是進行協議轉換,發送一個 ZigBee 控制指令到消息總線上的 topic: $iot/v1/ZigBee/Control。
- 由於 Proc_ZigBee 進程訂閱了這個 topic,因此它接收到這個控制指令。
- Proc_ZigBee 把控制指令轉換成 ZigBee 無線通信模塊要求的格式,通過硬件發送給設備燈泡。
我們再分析一下設備數據上報的場景:
先關注圖中紅色箭頭,忽略藍色箭頭:
- 門磁打開后,通過無線通信把信息上報給進程 Proc_CF。
- Proc_RF 進程接收到 RF433 通信模塊上報的數據,把“門磁打開”這個信息發送到消息總線上的 topic:$iot/v1/RF/Report。
- 由於 Proc_Protocol 進程訂閱了這個 topic,因此接收到上報的門磁數據。
- Proc_Protocol 分析數據,把 RF433 協議的數據轉成統一的應用層協議的數據,發送到消息總線上的 topic:$iot/v1/Device/Report。
- 由於 Proc_Bridge 進程訂閱了這個 topic,因此就接收到了這次上報的數據。
- Proc_Bridge 進程把數據上報給服務器。
再來看一下藍色箭頭流程:
在上面的第 4 步:Proc_Protocol 進程把 RF433 協議數據轉成應用層統一協議之后,把數據發送到消息總線上的 topic:$iot/v1/Device/Report 之后,Proc_Auto 進程同時進行如下操作:
- 由於 Proc_Auto 也訂閱了這個 topic,因此它也接收到了門磁上報的這個應用層協議的數據。
- Proc_Auto 查找自己的配置信息(假設用戶已經提前配置好了一條規則:當門磁打開的時候,就觸發聲光報警器),發現匹配到了“門磁->報警器”這條規則,於是發出一條控制報警器的指令,發送到消息總線上的 topic: $iot/v1/Device/Control。
后面的 7,8,9,10 這四個步驟就與上面的控制指令流程完全一樣了。
3.4 與 DBUS 總線的對比
從上面描述的 3 個數據流向的場景中,是不是感覺到使用 topic 為“數據管道”的這種通信方式,與 Linux 系統中的 DBUS 總線特別的相似?
DBUS 總線也是用於進程之間的通信,按照我個人的理解,DBUS中其實是把進程之間的兩種通信組織在一起了:
- 基於信號的數據傳輸;
- 基於方法的 RPC 遠程調用;
DBUS 總線包含的概念更復雜一些,包括:路徑、對象、接口、方法等等,這些概念組織在一起共同定位到一個具體的服務提供者了。
相比較而言,我感覺 MQTT 這樣的方式更簡潔一些。
所謂的 RPC 遠程調用,就是調用位於遠程機器上的一個函數,主要解決兩個問題:
- 網絡連接;
- 數據的序列化和反序列化;
后面我會專門寫一篇文章,利用 protobuf 框架來實現 RPC 調用。
四、網關與雲平台之間的通信
上面講解的設計過程,是網關內部的各功能模塊之間通信方式,這也是我們作為嵌入式開發者能充分發揮的部分。
網關與雲平台之間的通信方式一般都是客戶指定的,就那么幾種(阿里雲、華為雲、騰訊雲、亞馬遜AWS平台)。一般都要求網關與雲平台之間處於長連接的狀態,這樣雲端的各種指令就可以隨時發送到網關。
當然了,這些雲平台都會提供相應的 SDK 開發包,一般使用 MQTT 協議來連接雲平台的更多一些。在一些文檔中,會把位於雲端的 MQTT 服務器稱作 Broker,其實就是一個服務器。
進程 Proc_Bridge 的功能主要有 2 點:
- 與雲平台的數據傳輸通道;
- 協議轉換:把雲平台相關的協議轉換成網關內部的協議,以及相反的轉換。
也就是說:Proc_Bridge 進程需要同時連接到雲平台的 MQTT Broker 和網關內部的 MQTT 消息總線。在下一篇文章中,我們來專門講解這部分的內容,並提供一個實現橋接功能的代碼模板。
五、總結
作為一名嵌入式軟件開發人員,僅僅根據別人設計好的框架來填充代碼,時間久了就會有些倦怠,不知道技術提升的方向在哪里。仔細想想,其實方向挺多的:Linux 內核、文件系統、算法、應用程序設計等等。
這篇文章討論的內容還談不上架構設計,僅僅是一個簡單的物聯網網關內部各功能模塊的通信模型。如果你有機會設計類似的產品,不妨嘗試一下這樣的通信模型,當然你一定會設計的更好!
出處:https://www.cnblogs.com/sewain/p/14439288.html
=======================================================================================
物聯網網關開發:基於MQTT消息總線的設計過程(下)
一、前言
在上一篇文章中物聯網網關開發:基於MQTT消息總線的設計過程(上),我們聊了在一個物聯網系統的網關中,如何利用 MQTT 消息總線,在嵌入式系統內部實現多個進程之間的相互通信問題。
這個通信模型的最大幾個優點是:
- 模塊之間解耦合;
- 各模塊之間可以並行開發;
- 把 TCP 鏈接和粘包問題交給消息總線處理,我們只需要處理業務層的東西;
- 調試方便;
以上只是描述了在一個嵌入式系統內部,進程之間的通信方式,那么網關如何與雲平台進行交互呢?
在上一篇文章中已經提到過:網關與雲平台之間的通信方式一般都是客戶指定的,就那么幾種(阿里雲、華為雲、騰訊雲、亞馬遜AWS平台)。一般都要求網關與雲平台之間處於長連接的狀態,這樣雲端的各種指令就可以隨時發送到網關。
這一篇文章,我們就來聊一聊這部分內容。
在公眾號回復:mqtt,獲取示例代碼的網盤地址。
二、與雲平台之間的 MQTT 連接
目前的幾大物聯網雲平台,都提供了不同的接入方式。對於網關來說,應用最多的就是 MQTT 接入。
我們知道,MQTT 只是一個協議而已,不同的編程語言中都有實現,在 C 語言中也有好幾個實現。
在網關內部,運行着一個后台 deamon: MQTT Broker,其實就是 mosquitto 這個可執行程序,它充當着消息總線的功能。這里請大家注意:因為這個消息總線是運行在嵌入式系統的內部,接入總線的客戶端就是需要相互通信的那些進程。這些進程的數量是有限的,即使是一個比較復雜的系統,最多十幾個進程也就差不多了。因此,mosquitto 這個實現是完全可以支撐系統負載的。
那么,如果在雲端部署一個 MQTT Broker,理論上是可以直接使用 mosquitto 這個實現來作為消息總線的,但是你要評估接入的客戶端(也就是網關)在一個什么樣的數量級,考慮到並發的問題,一定要做壓力測試。
對於后台開發,我的經驗不多,不敢(也不能)多言,誤導大家就罪過了。不過,對於一般的學習和測試來說,在雲端直接部署 mosquitto 作為消息總線,是沒有問題的。
三、Proc_Bridge 進程:外部和內部消息總線之間的橋接器
下面這張圖,說明了 Proc_Bridge 進程在這個模型中的作用:
- 從雲平台消息總線接收到的消息,需要轉發到內部的消息總線;
- 從內部消息總線接收到的消息,需要轉發到雲平台的消息總線;
如果用 mosquitto 來實現,應該如何來實現呢?
1. mosquitto 的 API 接口
mosquitto 這個實現是基於回調函數的機制來運行的,例如:
// 連接成功時的回調函數
void my_connect_callback(struct mosquitto *mosq, void *obj, int rc)
{
// ...
}
// 連接失敗時的回調函數
void my_disconnect_callback(struct mosquitto *mosq, void *obj, int result)
{
// ...
}
// 接收到消息時的回調函數
void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
{
// ..
}
int main()
{
// 其他代碼
// ...
// 創建一個 mosquitto 對象
struct mosquitto g_mosq = mosquitto_new("client_name", true, NULL);
// 注冊回調函數
mosquitto_connect_callback_set(g_mosq, my_connect_callback);
mosquitto_disconnect_callback_set(g_mosq, my_disconnect_callback);
mosquitto_message_callback_set(g_mosq, my_message_callback);
// 這里還有其他的回調函數設置
// 開始連接到消息總線
mosquitto_connect(g_mosq, "127.0.0.1", 1883, 60);
while(1)
{
int rc = mosquitto_loop(g_mosq, -1, 1);
if (rc) {
printf("mqtt_portal: mosquitto_loop rc = %d \n", rc);
sleep(1);
mosquitto_reconnect(g_mosq);
}
}
mosquitto_destroy(g_mosq);
mosquitto_lib_cleanup();
return 0;
}
以上代碼就是一個 mosquitto 客戶端的最簡代碼了,使用回調函數的機制,讓程序的開發非常簡單。
mosquitto 把底層的細節問題都幫助我們處理了,只要我們注冊的函數被調用了,就說明發生了我們感興趣的事件。
這樣的回調機制在各種開源軟件中使用的比較多,比如:glib 里的定時器、libevent通訊處理、libmodbus 里的數據處理、linux 內核中的驅動開發和定時器,都是這個套路,一通百通!
在網關中的每個進程,只需要添加上面這部分代碼,就可以掛載到消息總線上,從而可以與其它進程進行收發數據了。
2. 利用 UserData 指針,實現多個 MQTT 連接
上面的實例僅僅是連接到一個消息總線上,對於一個普通的進程來說,達到了通信的目的。
但是對於 Proc_Bridge 進程來說,還沒有達到目的,因為這個進程處於橋接的位置,需要同時連接到遠程和本地這兩個消息總線上。那么應該如何實現呢?
看一下 mosquitto_new 這個函數的簽名:
/* * obj - A user pointer that will be passed as an argument to any * callbacks that are specified. */
libmosq_EXPORT struct mosquitto *mosquitto_new(const char *id, bool clean_session, void *obj);
最后一個參數的作用是:可以設置一個用戶自己的數據(作為指針傳入),那么 mosquitto 在回調我們的注冊的任何一個函數時,都會把這個指針傳入。因此,我們可以利用這個參數來區分這個連接是遠程連接?還是本地連接。
所以,我們可以定義一個結構體變量,把一個 MQTT 連接的所有信息都記錄在這里,然后注冊給 mosquitto。當 mosquitto 回調函數時,把這個結構體變量的指針回傳給我們,這樣就拿到了這個連接的所有數據,在某種程度上來說,這也是一種面向對象的思想。
// 從來表示一個 MQTT 連接的結構體
typedef struct{
char *id;
char *name;
char *pw;
char *host;
int port;
pthread_t tHandle;
struct mosquitto *mosq;
int mqtt_num;
}MQData;
完整的代碼已經放到網盤里了,為了讓你先從原理上看明白,我把關鍵幾個地方的代碼貼在這里:
// 分配結構體變量
MQData userData = (MQData *)malloc(sizeof(MQData));
// 設置屬於這里連接的參數: id, name 等等
// 創建 mosquitto 對象時,傳入 userData。
struct mosquitto *mosq = mosquitto_new(userData->id, true, userData);
// 在回調函數中,把 obj 指針前轉成 MQData 指針
static void messageCB(struct mosquitto *mosq, void *obj, const struct mosquitto_message *message)
{
MQData *userData = (MQData *)obj;
// 此時就可以根據 userData 指針中的內容分辨出這是哪一個鏈接了
}
另外一個問題:不知道你是否注意到示例中的 mosquitto_loop() 這個函數?這個函數需要放在 while 死循環中不停的調用,才能出發 mosuiqtto 內部的事件。(其實在 mosuiqtto 中,還提供了另一個簡化的函數 mosquitto_loop_forever)。
也就是說:在每個連接中,需要持續的觸發 mosquitto 底層的事件,才能讓消息系統順利的收發。因此,在示例代碼中,使用兩個線程分別連接到雲平台的總線和內部的總線。
四、總結
經過這兩篇文章,基本上把一個物聯網系統的網關中,最基本的通信模型聊完了,相當於是一個程序的骨架吧,剩下的事情就是處理業務層的細節問題了。
萬里長征,這才是第一步!
對於一個網關來說,還有其他更多的問題需要處理,比如:MQTT 連接的鑒權(用戶名+密碼,證書)、通信數據的序列化和反序列化、加密和解密等等,以后慢慢聊吧,希望我們一路前行!
在公眾號回復:mqtt,獲取示例代碼的網盤地址。
出處:https://www.cnblogs.com/sewain/p/14439290.html