王鑫 許智鴻 胡華昌 楊豐羽



摘要:隨著經濟社會的高速發展,“互聯網+”時代的到來,基于Online To Offline(020)商業模式的外賣配送行業迅速崛起,其發展前景一片廣闊,在提供方便快捷服務的同時也帶動了社會經濟的發展[1]。但是隨著外賣配送行業的進一步壯大,基于外賣配送的很多問題也日益凸顯,比如外賣偷盜和錯拿以及配送過程中帶來的交通安全和社會違法犯罪隱患等[2]。通過智能外賣自提柜系統,配送員將外賣暫存于智能外賣自提柜中,可以有效地解決外賣配送過程中出現的各種問題,安全有保障地將外賣送達到客戶手中[3]。本文通過對移動端APP、PC端Web信息管理平臺、設備端實體柜以及服務器四個部分的整體設計與分析來整合搭建一套完整可運行的智能自提柜系統,并較為詳細地對各部分之間交互通信方式的設計和實現原理進行了分析。
關鍵詞:智能外賣自提柜系統;Netty框架;Android;Flask MVC框架;stm32單片機;數據庫
中圖分類號:TP311 文獻標識碼:A
文章編號:1009-3044(2020)19-0010-04
開放科學(資源服務)標識碼(OSID):
1 智能外賣自提柜系統工作原理
智能外賣自提柜系統以服務器為中心,移動端和設備端通過自定義通信協議與服務器進行通信。系統采用前后端完全分離的設計模式,將系統數據庫搭建在服務器端,并對來自移動端和設備端的請求消息進行編解碼和事務處理。PC端平臺與服務器共享系統數據庫,實現系統數據的可視化管理,系統的總體設計圖如圖1所示。
2 服務器端開發
服務器端選擇完全異步非阻塞的Netty框架作為底層的通信框架,Netty是對NIO的優化和封裝,其API使用更簡單,開發門檻更低[4]。同時服務器整合了MyBatis框架來管理MySQL數據庫。服務器分為移動端服務器和設備端服務器兩部分。其中,Netty服務器創建啟動的時序圖如圖2所示。
2.1 移動端服務器開發
2.1.1移動端通信傳輸協議
移動端通信協議由數據頭部和消息兩部分組成,其中數據頭部的內容為消息長度,消息部分為傳輸的消息對象的Json格式字符串的二進制。同時,本系統選擇速度較快的阿里巴巴的Json轉換工具Fastj son來實現JavaBean與字符串之間的轉換。協議格式如圖3所示。
2.1.2 移動端通信框架的實現
TCP/IP協議是以字節為單位的流式的數據傳輸協議,數據之間是連續的沒有界限的,這就導致一次收到的數據幀可能不是完整的,也就是常見的TCP粘包/拆包問題。為了解決這個問題,Netty提供了很多數據編解碼器,來幫助開發人員更方便地完成數據的編解碼任務。
協議頭部的數據長度部分是由NetW提供的LengthField-Prepender自定義長度編碼器添加的,它可以計算當前待發送消息的二進制字節長度,將該長度添加到待發送數據的頭部。同時,在此之前還需要通過一個自定義編碼器來將傳輸對象轉換為JSON格式字符串,并進一步轉換為二進制數據。與自定義長度編碼器配套使用的是LengthFieldBasedFrameDecoder解碼器,通過該解碼器可以讀取數據幀頭部的長度部分,并會在此后連續讀取長度部分個字節,將這些字節作為一個完整的消息傳遞到下一個自定義消息解碼器中,進一步轉換為消息對象,再交給自定義事務處理器ServerHandler進行處理。
2.1.3移動端服務器事務處理
Android移動端的事務處理請求被封裝為一個Interacti-veRequest類,其內部的成員變量msgType表示該請求的事務類型。移動端發送給服務器的所有請求包括:注冊請求,登錄請求,訂單查詢請求,空柜查詢請求,存放請求,注銷請求等。當服務器端接收到移動端發來的消息時,首先經過解碼器將消息轉換為消息對象,然后在ServiceHandler的ChannelRead0方法中獲取其類型屬性,根據屬性的值確定其代表的事務類型,并進行相應的事務處理,最終返回給客戶端相應的處理結果。
2.2 設備端服務器開發
2.2.1設備端通信傳輸協議
服務器與設備實體柜之間使用自定義通信傳輸協議進行TCP通信,數據楨格式如下表l所示。部分指令類型的詳細設計如下表3所示。
2.2.2 設備端通信框架的實現
服務器端通過自定義解碼器DeviceDecoder來解決TCP粘包/拆包問題,當解碼器讀到四個連續的OxOa時才認為是讀到了一個數據幀的幀頭,并獲取其后兩個字節的幀長度,若Byte-Buf中剩余字節數量大于等于幀長度,則將幀頭后連續幀長度個字節作為一個完整的消息進行處理。否則,則認為發生了拆包現象,標記ByteBuf讀取位置,等待下一次讀取再處理。
本系統規定除應答消息外,不論是服務器端還是設備端對于接收到的其他指令都必須回復一個應答消息來通知另一端已經接收到正確信息。但是考慮到在通信過程中可能會發生數據丟失或者數據出錯等情況,所以系統規定對于丟失或者出錯的數據均采取丟棄處理,不予應答,并制定了相應的指令超時重傳和指令重復不處理的機制。對于服務器端來說:
(1)對于接收的設備端指令的處理
服務器端在每個設備端對應的服務器端DeviceHandler中維護一個已接收并處理指令集ReceiveMap和一個已發送但未應答指令集SendMesMap,分別用來存儲已成功接收到的設備端的指令Frameld和已發送的但還未收到應答的服務器端指令Frameld,則存在以下情況:
若設備端指令在傳輸過程中丟失或者校驗和檢驗出錯,服務器端采用丟棄處理,不予應答。
若設備端指令完整接收,且校驗和無誤,則立即返回給設備一個應答消息指令,其Frameld為接收的設備端消息的編號,表示對于設備傳輸的該編號指令已經接收并且無誤。并且將該指令的編號存儲到相應的ReceiveMap中,表示該指令已處理過,防止由于應答消息丟失導致的設備端重傳指令的重復處理。
若設備端指令為應答指令,則將SendMesMap中相應編號的已發送服務器端指令進行刪除。
(2)對于發送的服務器端指令的處理
對于服務器端發送給設備端的指令采用超時重傳機制。使用scheduleAtFixedRate0方法在每個設備對應的服務器端線程中開啟一個定時器,每隔一段時間都會將相應SendMesMap中還沒收到應答的指令進行重傳。
2.2.3 設備端服務器事務處理
由于各類型指令除Content部分外其它部分數據格式以及整體編解碼方式都一致,所以采用模板方法模式設計指令類。服務器端將父類指令封裝為Devlnstruction抽象類,各類型指令封裝為類Devlnstruction000-006.均繼承自父類指令。其中,父類中給出整體指令編解碼的邏輯骨架,Content部分的編解碼方法以及指令的具體業務處理邏輯被設置為抽象方法,在子類中進行方法的掛鉤和具體實現。
為了更好地管理設備和用戶,向不同的設備和用戶主動的發送消息,服務器維護了ChanneIDevList和ChanneIUserList列表來管理在線設備和用戶,并使用Collections.synchronizedList0方法對List進行包裝來獲取一個線程安全的List。同時在線列表提供了對指定用戶或設備的消息發送方法,允許服務器對指定的設備和用戶進行消息傳輸,實現了設備端服務器和設備服務器之間的通信。
3 移動端開發
3.1 Netty通信客戶端的整合
移動端選擇廣泛使用的Android平臺開發移動端手機APP.Android APP需要通過Netty客戶端與服務器端進行自定義協議通信,所以需要將移動端程序與Netty客戶端框架進行整合,其中,Netty客戶端創建啟動的時序圖如下圖4所示。
Application是Android的一個系統組件,Android系統會為每個程序運行時創建一個Application類的對象且僅創建一個,因為它是全局的單例的,所以我們將Netty客戶端搭建在自定義的Application組件中,并對外提供與服務器傳輸消息的方法來實現通信。在程序啟動時,系統就在Application的OnCreate0方法中初始化Netty客戶端連接。
4 PC端開發
PC端在Python主流開發語言環境下,利用Flask工具搭建一個可高效擴展開發的基于MVC的自提柜信息管理平臺[6],同時使用SQLAlchemy創建ORM模型,然后利用ORM模型對數據庫進行操作。開發簡單快捷,拓展性極強,運行效率較高。同時采用了Nginx、uWSGI的部署模式,提高了服務的并發能力。
4.1 服務器架構
PC端設計了Web服務器、應用服務器、Web應用以及數據庫服務器的四層服務器架構,其交互邏輯如下圖5所示。
Nginx作為直接對外的服務接口,負責接收客戶端發送過來的HrITP請求。當用戶端發起HTTP請求時,如果是靜態文件請求,Nginx就根據Nginx配置的靜態文件目錄返回請求的靜態資源;如果是動態請求,Nginx就通過配置文件將請求傳遞給uWSGI。uWSGI根據請求的URL調用Flask App對應的函數。涉及數據庫的部分,便通過SQIAlchemy高效訪問MySQL數據庫,并返回數據庫操作結果給Flask。
全部處理完后Flask將結果轉發回uWSGI,uWSGI接收后轉發回Nginx,Nginx最終將結果返回給客戶端。
4.2 MVC框架搭建
MVC框架(Model View Controller)是一種將應用程序的邏輯層和視圖層相分離設計,并通過控制層連接的開發模式[7]。其中模型、視圖、控制器三個核心部件構成了整個Web應用程序。在本系統中,通過對Flask原生的MVC架構進行改裝[8],框架的工程目錄設計清晰明了,各部分功能明確,當開發人員使用MVC框架進行二次開發時,只需要根據自己開發任務的要求,對各個目錄功能進行擴展和善即可高效開發。
5 設備端開發
設備端硬件平臺基于stm32單片機,使用WIFI模塊和GPRS模塊實現通信功能,支持WIFI網絡和運營商網絡,滿足多數投放環境的需要。軟件平臺基于FreeRTOS實時操作系統,平衡單片機資源和設備功能需求,保證設備交互和通信的實時性,設備投放簡單,易于維護,具有高可擴展性。
5.1硬件設計
設備硬件由通信模塊、設備交互模塊、控制核心和轉接模塊構成,其中轉接模塊根據設備功能需求定制,不同的轉接模塊可以組建不同配置的柜體。
(1)通信模塊:采用SIM800+ESP8266模塊,二者都通過AT指令與單片機通訊,可根據投放地的網絡情況選擇不同的連接方式。
(2)設備交互模塊:包括按鍵和顯示屏,當前方案為按鍵輸入取貨密碼,顯示屏提示信息,設備后續迭代升級較為方便,例如按鍵輸入可升級為掃描二維碼。
(3)控制核心:使用stm32f103RBT6,片內有20k字節RAM,128k字節flash,滿足系統運行和數據緩存的需求,支持捧電檢測,當外部斷電時,切換至內部電源供電,同時向服務器報警,當內部電源電量過低時,進入掉電模式,所有緩存數據存人flash中,保證掉電后設備數據不丟失,同時通知服務器,等待維護人員更換電源。
(4)轉接模塊:考慮到設備的多樣化和可擴展性,硬件設計中,將柜體的控制部分獨立,做成轉接模塊,由于設備電鎖等開關型器件較多,10口資源有限,轉接模塊中使用74HC595等串人并出的IC節省輸出10口,轉接模塊板載了stm32f0單片機,實現柜體中數字傳感器數據采樣和處理。
5.2 軟件設計
軟件設計中的任務設計框圖如圖7所示。由于設備與服務器之間吞吐數據量小,指令固定,因此使用自定義通信協議,除了協議格式的確定.還需加入應答機制、數據重發機制。每條指令有唯一的Frameld,指令發送后,接收方會返回對應Fra-meld的應答幀,如指定時間內未收到應答,則需重發。
利用FreeRTOS動態分配任務棧的特點,可以方便得實現上述需求,本設計通過動態創建和刪除數據重發任務實現多條指令并行的應答等待和數據重發。設計中用到數據解析任務和數據重發任務。
(1)數據解析任務:解析接收到的指令,指令分為應答幀和非應答幀,非應答幀包含服務器的控制指令,應答幀包含其父指令的Frameld(將每幀數據稱為其對應的應答幀的父指令)。數據解析任務如果收到應答幀,會將其中包含的Frameld存人消息隊列MsgBox_Rpy中。
(2)數據重發任務:每條指令發送后都會根據Frameld創建唯一的數據重發任務,任務被創建后,執行如下操作:
申請內存,將該幀數據緩存。
每5s檢測一次消息隊列MsgBox_Rpy,檢測完成則重發數據,最多重發3次,3次后刪除本任務。
如果檢測到MsgBox_Rpy中有數據,則判斷其中的數據是否和本任務的Frameld匹配,如果匹配,則刪除本任務。
參考文獻:
[1]張文紅.020模式下的餐飲外賣行業分析研究[J].農村經濟與科技,2019,30(474):124-125.
[2]黃子成,網絡外賣引發的社會治安問題及綜合治理對策研究[J].現代商貿工業,2018,39:151-153.
[3]王恩全,李鑫雨,劉雪薇,等.互聯網時代保溫自提柜在外賣配送行業的應用與展望[J].中國市場,2019(17):161-162.
[3]王恩全,李鑫雨,劉雪薇,等.互聯網時代保溫自提柜在外賣配送行業的應用與展望[J].中國市場,2019(17):161-162.
[4]魏瑩.基于Netty框架的智能終端與服務器通信的研究[Dl.西安:西安電子科技大學,2017.
[5]李林鋒.Netty權威指南[M].北京:電子工業出版社,2014:11-45.
[6]李超,徐云龍,華中偉,等.一種基于Python Flask的Web服務器端設計[J].信息與電腦,2019(8):87-88.
[7]李守振,張南平,常國鋒.Web應用分層與開發框架設計研究[Jl.計算機工程,2006,32(22):274-276.
[8]邊蓓蓓,于萍.MVC模式在Web中的應用研究[J].信息技術與信息化,2015(6):82-83.
【通聯編輯:李雅琪】
收稿日期:2020-03-27
作者簡介:王鑫(1999-),男,山東泰安人,山東科技大學,本科;許智鴻(1998-),男,山東菏澤人,山東科技大學,本科;胡華昌(2000一),男,湖北黃岡人,山東科技大學,本科;楊豐羽(1999-),男,山東青島人,山東科技大學,本科。