伍 新
(航空工業西安航空計算技術研究所 陜西 西安 710068)
在嵌入式領域,軟件通常采用單體架構,在該架構下,開發者能夠在軟件系統設計的同時設計各個電子控制單元(electronic control unit, ECU)的通信系統;嵌入式系統處理的數據量相對較小,對帶寬的依賴也較小,一般采用控制器局域網總線(controller area network, CAN)面向信號的方式來設計通信系統[2]。
隨著芯片工藝和通信技術的發展,軟硬系統的處理能力進一步提升,業界為解決單體架構可擴展性差的瓶頸,將互聯網技術領域中面向服務的軟件架構(service-oriented architecture, SOA)引入嵌入式領域[3],SOA是面向服務的架構,整個系統由一個個服務組裝而成,各服務內部體現為高內聚特性,服務之間則是體現為低耦合特性[4],因其高內聚、低耦合、拓展性強等特性,為單體架構的拓展性差、維護成本高的問題提供了一種可行的解決方案。以太網因其具有應用廣泛、通信速率較高、成本低廉和可持續發展潛力大等優勢[5]備受開發者青睞,為了解決網絡數據處理的技術瓶頸,將以太網應用于該領域,鑒于可擴展性和以太網相適應的需求設計了SOMEIP。
SOMEIP采用客戶端服務器的通信架構,客戶端可根據服務接口類型,使用遠程服務調用機制,通過數據序列化與反序列化使得數據可以在網絡中傳輸,通過服務發現機制來動態地獲取可用的服務實例,通過發布訂閱機制來管理服務的發布與訂閱關系。該協議隸屬于應用層,且緊靠傳輸層,為具體業務邏輯提供調用接口,同時提供數據的封裝與解封功能。
面向信號的通信,消息發送方會將發送內容放到一個緩沖區中,緩沖區的數據會按照CAN總線配置的周期發送至對端緩沖區,待對端使用數據時就從緩沖區中取出。該設計未考慮數據的供需關系,可能造成負載過重。面向服務的通信,則是規避了這一缺陷,實現了按需通信,同時為避免對同一服務的多次調用,提供了發布訂閱機制,實現了一次訂閱,多次接收。
此外SOMEIP作為通信中間件,實現了業務邏輯與底層通信之間的解耦,上層業務的擴展不會影響底層通信的運行,具有很好的擴展性。
SOMEIP的特點是采用面向服務的設計模式,將原有的功能模塊抽象成一個個具體的服務,ECU在需要某項功能時,可以通過它來跨ECU異步調用具體服務。其核心優勢包括:(1)滿足嵌入式領域對軟硬件資源的限制。(2)具有很好的兼容性,如文獻[6]給出的SOMEIP與CAN之間的數據轉換。(3)可從小平臺擴展到大型平臺,可以在不同的操作系統上實現,甚至可以在沒有操作系統的情況下實現。
SOMEIP協議是以服務為單位管理數據信息的,服務由若干方法、事件和域構成。方法是服務的某項具體功能,是客戶端調用的對象。事件用于發布訂閱,可以周期性或者當事件觸發時向訂閱者主動發送信息,其內嵌一個消息結構,服務方可自定義所要發送的內容。域是針對服務中的某個具體屬性而設計的,主要對外提供屬性的獲取、設置和通知接口,客戶端可通過獲取和設置接口實現對服務端屬性值的獲取與設置,當客戶端訂閱該域時,通知還可以像事件一樣,主動提供通知,此兩者的區別在于消費者在訂閱域后,通知會主動通知消費者,而事件不會。
SOMEIP就這3種接口提供對應的通信機制,分別是基于方法通信、基于事件通信和基于域通信。其中基于方法通信又根據是否需要返回值而分為請求有回復和請求無回復2種。在基于方法通信中請求有回復和請求無回復的區別在于前者具有返回值,可以保證遠程過程調用的正確性,而后者則是無返回值的,因此對于遠程過程調用正確與否不得而知。其通信機制如圖1所示。

圖1 SOMEIP通信原理圖
客戶端與服務端在收發消息時,有多種通信機制,選擇何種通信機制取決于消息類型的選擇,協議定義的消息類型如表1所示。

表1 消息類型
對于請求有回復通信,客戶端可創建REQUEST類型的消息,并得到服務端發來的RESPONSE類型的消息;對于請求無回復通信,客戶端僅需創建REQUEST_NO_RETURN類型的消息,通過接口發給對端即可。至于事件通信和域中的通知,服務端會創建NOTIFICATION類型的消息發給訂閱者。
VSOMEIP是SOMEIP的開源框架,實現了SOMEIP協議中提出的各項功能,該框架解決了微服務框架中注冊中心單一而造成的單點故障問題。
VSOMEIP通過一個應用對外提供一套接口來給用戶使用,在該應用中內嵌一個路由對象來實現該框架的核心功能。路由對象又分為主模式和代理模式,其中主模式下的路由對象充當注冊中心和網關的角色,代理模式下的路由對象充當代理路由的角色,代理路由將核心業務發給主路由處理。在本地可以有多個應用,只有一個應用的路由對象是主路由,其他應用的路由對象是代理路由,可以通過配置文件設置主路由,默認第一個應用中的路由對象為主路由。其結構如圖2所示。

圖2 框架結構圖
其中代理處理對象主要處理本地邏輯,遠程邏輯則是通過服務發現對象生成對應報文并由主路由廣播。
VSOMEIP采用的IP地址為基本端口+偏移量的方式,其中偏移量就是每個應用的ID值。主路由模式下的應用,在初始化時就獲取了該ID,而其他應用在開始工作前需要向主路由注冊,一方面是獲取ID值,另一方面則是維護與主路由的連接。注冊完成后,就可以回調對應的接口來進行后續邏輯,比如服務端執行服務以及事件的注冊、客戶端執行服務的請求調用與事件的訂閱等。
服務端服務或者事件的注冊都是向本地注冊中心發送一個注冊命令和注冊信息,在注冊中心生成對應對象并保存到對應列表中,區別在于服務注冊后會通過注冊中心的服務發現對象生成并廣播發布報文而事件不會,原因在于事件在邏輯上是隸屬于某個服務的,此外服務注冊完成后還會利用本地的請求列表通知對應的請求者。
客戶端請求某服務實例的具體方法以及訂閱某事件都是通過應用來實現的,在初始化時會將自定義的函數綁定到應用對應結構中,等到條件滿足時回調對應函數。對于本地邏輯,請求某個服務時會向主路由發送對應命令,主路由會告知對應服務的ID,然后客戶端就可以發起連接并將消息發送到對端;對于遠程邏輯則是通過服務發現對象生成并廣播尋找服務的報文,獲取到對應ID后在主路由端維護與遠程服務的連接,客戶端在調用時會先將消息發給主路由,然后通過該連接發送到遠端。事件的訂閱則是在事件的列表中添加對應應用的ID,本地與遠程的區別在于本地只需要發送對應命令給主路由,而遠程則需要主路由生成并廣播對應報文。
服務發現是實現遠程服務發布發現以及事件訂閱的功能組件,其核心任務是了解服務的狀態和位置。當服務端與客戶端不在同一機器時,則通過該模塊產生并廣播服務發現報文來完成。服務發現報文采用條目+選項的方式實現服務的遠程發布與發現、事件的遠程訂閱與取消等功能。條目對服務發現的功能進行抽象,根據用于服務和事件分為2大類,其具體分類和功能如表2所示。

表2 條目類型及功能
選項是用來輔助條目實現其功能的,提供條目缺乏的一些輔助信息,主要用來告知對方本節點業務的IP和端口信息,以便對方能通過該地址進行通信。
本小節結合VSOMEIP,設計了嵌入式設備蜂鳴器服務的案例,如下所示:
Classbuzzer_server{
Public:
Buzzer_server() :app_(vsomeip::runtime::get()->create_application()),
state(false),volume(0){}
Voidinit(){}}--------------//app_initandbindon_Xintovsomeip
Voidstart(){}--------------//app_start
Voidstop(){}-------------------//unregisteron_Xandapp_stop
Voidon_open(){}----------//F&Fopenthebuzzer
Voidon_close(){}---------//F&Fclosethebuzzer
Voidon_state(){}----------------//testtheAPPisregisterediftruethenoffer_service
Voidon_set_volume(){}--------//fieldsetter
Voidon_get_volume(){}---------//fieldgetter
Voidon_notify_volume(){}-------//fieldnotifier
Private:
std::shared_ptr
Boolstate;//stateupordown
Unsignedintvolume;//voicelevel
};
本案例中只有一個開關state和音量volume以及用于和VSOMEIP框架相連接的app_,默認開關是關閉狀態,音量為0;buzzer_server接口是本案例的構造函數;init、start和stop接口分別是本案例的初始化和開關接口,在初始化過程中須先對app_進行初始化,且在app_初始化完成后需要將自定義的接口通過app_對應接口綁定到VSOMEIP框架以備后續回調處理,開關接口則是通過app_調用VSOMEIP的開關接口;on_open和on_close接口則是蜂鳴器的開關接口,用戶可通過請求有返回值方式來開啟和關閉蜂鳴器;on_get_volume、on_set_volume和on_notify_volume_change接口則是針對volume字段而設計的field,用戶可通過請求有返回的方式調用前兩個接口來獲取以及設置音量大小,后者是一個通知接口,當音量發生變化時主動通知音量的訂閱者。
VSOMEIP的核心優勢是實現了SOA,并解決了注冊中心單點故障的問題,同時實現了SOMEIP協議中定義的服務的注冊與動態發現機制以及發布訂閱機制,實現了客戶端與服務端之間的按需通信,降低了網絡負載,解決了面向信號通信中數據處理規模較小,數據發送未考慮對端需求從而造成網絡過載的問題,同時也實現了協議中消息頭部的序列化與反序列化功能。
同時該框架也存在一些不足之處:一是它目前是依賴于C++,且不能自動生成代碼;二是它缺乏對復雜數據類型的序列化與反序列化處理,需要手動按照協議來處理,對開發人員不太友好,可能會降低開發效率,該框架中對服務實例全生命周期管理并未實現。針對前者,可以引入一個中間層來過渡,例如可以采用諸如ProtoBuf這類插件來生成不同語言的服務接口,并在服務中內嵌一個VSOMEIP的應用來實現,對外可以支持多語言,底層還是采用C++;針對復雜接口序列化與反序列化問題,可以將復雜數據類型定義成json格式,然后使用boost中的屬性樹,將json轉為屬性樹,拓展VSOMEIP消息處理接口,使其能夠加載boost屬性樹。針對服務實例全生命周期的管理,則可以拓展原框架中服務注冊接口,添加服務實例的生命周期,并設計一個接口,周期性地判斷該服務實例生命周期是否歸零,如服務實例到期,則可進行后續下線處理。