客戶有一堆小設備,需要通過小程序來控制它們,主要是設備門的開關、電源開關、狀態查詢、壓力控制等。下面主要紀錄下設計思路。
源碼地址:https://gitee.com/bxjg1987_admin/abp
視頻講解地址:https://www.bilibili.com/video/BV1M5411j7Lo?from=search&seid=14452337061864244964
最初的設計是這樣的
核心流程有3個,分別用綠、藍、黑這3種顏色來標識。
流程1:小程序端發送指令控制設備(開關、艙壓調整等)
以開關電源控制為例
- 小程序向wei服務端發起請求,說我想關閉設備id為1的那個設備
- wei服務端准備一條消息(說我要關閉id為1的那個設備),發送給RabbitMQ消息隊列
- RabbitMQ消息隊列將消息推送給硬件服務器
- 硬件服務器解析消息,根據設備id和按協議約定准備byte[]指令下發給具體設備
- 設備回復消息給硬件服務器
- 硬件服務器組織一條回復消息(所id為1的設備已經關閉成功)發送給RabbitMQ消息隊列
- 消息隊列將回復消息推送給web服務端
- web服務端通過abp提供的通知功能(默認基於a's'p.net core signalr)通知小程序端,
此時小程序端開源認為操作成功,但是不是太准確,另一種辦法是小程序再查一次設備狀態確認下。所以上面的步驟5可以向設備觸發一個請求,讓設備立即上報一次數據。默認情況下設備是輪詢的比如30秒上報一次數據。
流程2:設備輪詢30秒上報一次數據
- 設備上報狀態數據
- 硬件服務器將設備狀態數據存儲到數據庫
- 硬件服務器向RabbitMQ消息隊列發送一條消息,說設備id為x的設備上報了狀態數據
- RabbitMQ消息隊列將消息推送給web服務端
- web服務端通過abp提供的通知機制通知小程序端
步驟3沒必要直接將狀態數據推送給消息隊列,因為此消息的接收方未必關系具體的數據,目前設計只是說有設備狀態上報了,這個消息通知到接收方,由接收方決定是否主動來查設備狀態
流程3:小程序主動查詢設備狀態
這個就比較簡單了
- 小程序端向web服務端發起查詢請求
- web服務器直接從數據庫查詢設備狀態返回就可以了
有點問題,這樣查詢不是設備的當前狀態,我們可以再定義接口直接去查一次當前設備的狀態,但是這樣編碼比較大,也不利於我們復用現有流程。最簡單的辦法是定義一個接口,向設備發送一條指令說請你立即上報一次數據,小程序原有的查詢設備狀態查到就是最新的了。
設備服務端SuperSocket
開源地址:https://github.com/kerryjiang/SuperSocket,這是個設計得比較好的,基於.net core的socket的通信框架。官方有文檔學起來比較簡單。
它負責與設備通信,可以單獨部署在一台服務器上。
基於Abp的Web服務端
這就不多說了,因為它已經為我們提供了很好的web服務端基礎設施,免得從頭做起。此服務端也可以單獨部署一台服務器
消息隊列RabbitMQ
其它mq沒用過,就用它咯。它主要是解耦設備服務端和web服務端的,主要是它可以主動推送消息給接收方,也可以考慮使用redis的推送來實現。消息隊列也可以單獨部署一台服務器
簡化后的設計
如果設備比較少,請求量不大可以用下面這種簡化的設計
既然是簡化,流程就不說了。主要是省略了消息隊列,並且省略了指令回復的處理,而是使用輪詢的方式,比如每過10秒查一次當前設備狀態,控制設備時,只是下發指令,而不等結果,因為我們的輪詢會查到下一次的設備狀態。
這里有些注意:
- 設備上報狀態存入數據庫時可以使用一個全局的數據庫連接
- web服務器向設備服務器發送指令時也可以考慮使用全局的tcp連接
- web服務器向設備服務器發送指令時可以使用supersocket提供的客戶端庫
結束
簡化后的方案最low,但是也最容易實現,目前源碼中就是采用的這種方式。前一種方式稍微好點,3台服務器可以分開部署,如果並發再大點可以考慮下分布式了,再不行就放棄這個上思路,直接上個阿里雲IOT啥的。