我們已經(jīng)可以基于vsomeip實(shí)現(xiàn)SOME/IP應(yīng)用,并且服務(wù)端和客戶端之間進(jìn)行消息的通信,消息的內(nèi)容稱為Payload。
但是設(shè)想一下,如果當(dāng)我們需要傳遞的消息內(nèi)容是一個(gè)比較復(fù)雜的數(shù)據(jù)結(jié)構(gòu),比如一個(gè)結(jié)構(gòu)體,一兩個(gè)倒也沒(méi)事,多了以后,Payload的打包、解析和聯(lián)調(diào)都會(huì)是件麻煩的事。
這時(shí),我們會(huì)想到序列化,比如用Google Protocol Buffer之類的,是不是可以解決問(wèn)題呢?
對(duì)于非AUTOSAR設(shè)備之間的通信,是可以解決的,但對(duì)于與AUTOSAR設(shè)備之間的通信,恐怕就行不通了,因?yàn)镻ayload是需要遵循AUTOSAR規(guī)范的,如圖:
于是,我們又會(huì)想到,如果有人能把序列化這一步也幫我們做好那就更好了,這就是RPC(Remote Procedure Call,遠(yuǎn)程過(guò)程調(diào)用)可以做到的事了。
GENIVI的CommonAPI C++是基于vsomeip實(shí)現(xiàn)的RPC框架,今天就讓我們一起看一下它是怎么用的吧~
搭建CommonAPI的開(kāi)發(fā)環(huán)境,有點(diǎn)費(fèi)勁的,除了依賴于boost和vsomeip,還有CommonAPI和CommonAPI-SomeIP,以及C++代碼生成工具,這里就不一一說(shuō)明了,我已經(jīng)整理好,放在Github上,關(guān)注公眾號(hào),回復(fù)“演示代碼”,可以獲得項(xiàng)目鏈接。
環(huán)境OK了以后,我們可以就創(chuàng)建第一個(gè)HelloWorld工程了,按照如圖所示CommonAPI的工作流程:
其中,F(xiàn)rancaIDL是一種接口描述語(yǔ)言,和編程語(yǔ)言無(wú)關(guān)。fidl文件是用IDL寫(xiě)的,它描述了服務(wù)提供的接口信息,包括類型(比如method、broadcast、attribute等)、參數(shù)、返回值。
創(chuàng)建HelloWorld.fidl文件:
package commonapi
interface HelloWorld {
version {major 1 minor 0}
method sayHello {
in {
String name
}
out {
String message
}
}
}
fdepl文件描述了服務(wù)的部署信息,包括Service ID、Instance ID、Method ID、Event ID等。
創(chuàng)建HelloWorld.fdepl文件:
import "platform:/plugin/org.genivi.commonapi.someip/deployment/CommonAPI-SOMEIP_deployment_spec.fdepl"
import "HelloWorld.fidl"
define org.genivi.commonapi.someip.deployment for interface commonapi.HelloWorld {
SomeIpServiceID = 4660
method sayHello {
SomeIpMethodID = 123
}
}
define org.genivi.commonapi.someip.deployment for provider as MyService {
instance commonapi.HelloWorld {
InstanceId = "test"
SomeIpInstanceID = 22136
}
}
CommonAPI代碼生成工具幾乎支持Franca的全部功能。
用準(zhǔn)備好的工具生成代碼:
commonapi-core-generator-linux-x86_64 -sk ./fidl/HelloWorld.fidl
commonapi-someip-generator-linux-x86_64 ./fidl/HelloWorld.fdepl
在src-gen/v1/commonapi目錄里,可以看到如下這些生成的代碼文件:
萬(wàn)事俱備,可以開(kāi)發(fā)應(yīng)用程序咯~
對(duì)于服務(wù)端,主程序代碼如下:
std::shared_ptr
其中,HelloWorldStubImpl是繼承于工具生成的HelloWorldStubDefault:
class HelloWorldStubImpl: public v1_0::commonapi::HelloWorldStubDefault {
public:
HelloWorldStubImpl();
virtual ~HelloWorldStubImpl();
virtual void sayHello(const std::shared_ptr;
};
HelloWorldStubImpl實(shí)現(xiàn)了sayHello接口,正如fidl定義的,當(dāng)客戶端發(fā)送name,回復(fù)“Hello name !”:
void HelloWorldStubImpl::sayHello(const std::shared_ptr
{
std::stringstream messageStream;
messageStream << "Hello " << _name << "!";
std::cout << "sayHello('" << _name << "'): '" << messageStream.str() << "'\\n";
_reply(messageStream.str());
};
對(duì)于客戶端,主程序如下:
std::shared_ptr < CommonAPI::Runtime > runtime = CommonAPI::Runtime::get();
std::shared_ptr
客戶端不需要實(shí)現(xiàn)接口,直接使用工具生成的HelloWorldProxy就可以了。
編譯運(yùn)行的結(jié)果如下:
現(xiàn)在再看一下應(yīng)該選擇CommonAPI還是vsomeip呢?用vsomeip的話,依賴的東西少,Payload的打包和解析要自己寫(xiě),工作量大,自由發(fā)揮的空間也大,用CommonAPI的話,依賴的東西多,環(huán)境搭建相對(duì)復(fù)雜,接口可以用IDL描述,這在SOA中非常有用,很多代碼由工具生成,基本通信幾乎不需要聯(lián)調(diào),主要的開(kāi)發(fā)工作是實(shí)現(xiàn)服務(wù)的接口,相當(dāng)于填充業(yè)務(wù)邏輯,工作量少,同時(shí)可以發(fā)揮的空間也小。很多事都是這樣吧,獲得便利的同時(shí)也會(huì)損失一些自由,如何選擇還是要具體分析。
通過(guò)這個(gè)示例,我們看到使用RPC通信和上一篇中基于消息的通信是截然不同的編程體驗(yàn),RPC讓客戶端可以像調(diào)用本地函數(shù)一樣調(diào)用服務(wù)端的函數(shù),很顯然它們并不在同一個(gè)進(jìn)程中,這是如何做到的呢?
下面,我們結(jié)合一張經(jīng)典的RPC原理框圖來(lái)看一下客戶端的sayHello到底是怎么調(diào)到服務(wù)端的sayHello的:
1.client調(diào)用本地接口sayHello,HelloWorldProxy就是client的stub(樁),負(fù)責(zé)將sayHello的參數(shù)進(jìn)行打包,組裝成一個(gè)或者多個(gè)網(wǎng)絡(luò)請(qǐng)求(這些取決于通信協(xié)議和序列化方式);
2.client的stub通過(guò)socket向server的stub,也叫skeleton(骨架),發(fā)送請(qǐng)求;
3.skeleton通過(guò)socket接收到請(qǐng)求;
4.請(qǐng)求消息被發(fā)送到skeleton,在這里就是HelloWorldStubDefault,負(fù)責(zé)將收到的請(qǐng)求拆包,取得client發(fā)送的參數(shù);
5.HelloWorldStubDefault把參數(shù)發(fā)給了HelloWorldStubImpl的sayHello。
6.server在HelloWorldStubImpl的sayHello里處理了請(qǐng)求,通過(guò)sayHelloReply_t將返回值發(fā)給了HelloWorldStubDefault,它負(fù)責(zé)把返回值進(jìn)行打包,組裝成一個(gè)或者多個(gè)網(wǎng)絡(luò)響應(yīng);
7.server的skeleton通過(guò)socket向client的stub發(fā)出響應(yīng);
8.stub通過(guò)socket接收到響應(yīng)消息;
9.響應(yīng)消息被發(fā)送到client的stub,也就是HelloWorldProxy,它負(fù)責(zé)將響應(yīng)消息進(jìn)行解析,取得server發(fā)送的參數(shù);
10.client通過(guò)HelloWorldProxy的sayHello,得到了returnMessage。
至此,client完成了一次RPC調(diào)用~
可以看出,在RPC框架中,樁的實(shí)現(xiàn)原理是非常關(guān)鍵的,它屏蔽了網(wǎng)絡(luò)通信的實(shí)現(xiàn),讓客戶端可以像調(diào)用本地接口一樣調(diào)用服務(wù)端提供的接口,而不用關(guān)心用的什么通信協(xié)議、序列化方式,以及所有的通信細(xì)節(jié)。
CommonAPI的樁是由代碼生成器根據(jù)IDL生成的,而在有的RPC框架里,還可以用動(dòng)態(tài)代理的方式得到。
審核編輯:劉清
-
AUTOSAR
+關(guān)注
關(guān)注
10文章
375瀏覽量
22473 -
RPC
+關(guān)注
關(guān)注
0文章
111瀏覽量
11829 -
SOA
+關(guān)注
關(guān)注
1文章
300瀏覽量
28081
發(fā)布評(píng)論請(qǐng)先 登錄
看一下射頻電路中的那些無(wú)源器件


一起探討一下這個(gè)可行?
SPC560Bxx OSAL組件不能與C++一起使用
C++軟件設(shè)計(jì)基礎(chǔ)考試題庫(kù)快來(lái)復(fù)習(xí)一下吧!
看一下SMART高速計(jì)數(shù)向?qū)У膽?yīng)用
一起來(lái)看一下藍(lán)牙版本到現(xiàn)在都經(jīng)歷了哪些變化
今天我們大家一起來(lái)探討一下關(guān)于PCBA生產(chǎn)中的問(wèn)題
今天我們大家一起來(lái)探討一下關(guān)于PCBA生產(chǎn)中的問(wèn)題
帶大家一起體驗(yàn)一下Vivado的ECO流程

34種自動(dòng)控制原理圖展示,了解一下吧

將Arduino庫(kù)與Raspberry Pi Pico C/C++ SDK一起使用

mpo光纖跳線規(guī)格參數(shù)你清楚嗎?一起來(lái)了解一下吧

盤(pán)點(diǎn)一下CST電磁仿真軟件的求解器

評(píng)論