想了解SOME/IP协议,可以移步:

SOME/IP 协议介绍

SOME/IP-SD 深入浅出

上一篇,我们已经可以基于vsomeip实现SOME/IP应用,并且服务端和客户端之间进行消息的通信,消息的内容称为Payload。但是设想一下,如果当我们需要传递的消息内容是一个比较复杂的数据结构,比如一个结构体,一两个倒也没事,多了以后,Payload的打包、解析和联调都会是件麻烦的事。

这时,我们会想到序列化,比如用Google Protocol Buffer之类的,是不是可以解决问题呢?对于非AUTOSAR设备之间的通信,是可以解决的,但对于与AUTOSAR设备之间的通信,恐怕就行不通了,因为Payload是需要遵循AUTOSAR规范的,如图:

于是,我们又会想到,如果有人能把符合AUTOSA规范的序列化这一步也帮我们做好那就更好了,这就是RPC(Remote Procedure Call,远程过程调用)可以做到的事了。GENIVI的CommonAPI C++是基于vsomeip实现的RPC框架,今天就让我们一起看一下它是怎么用的吧~

搭建CommonAPI的开发环境,有点费劲的,除了依赖于boost和vsomeip,还有CommonAPI和CommonAPI-SomeIP,以及C++代码生成工具,这里就不一一说明了,我已经整理好,放在Github上,关注公众号,回复“演示代码”,可以获得项目链接。

环境OK了以后,我们可以就创建第一个HelloWorld工程了,按照如图所示CommonAPI的工作流程:

其中,FrancaIDL是一种接口描述语言,和编程语言无关。fidl文件是用IDL写的,它描述了服务提供的接口信息,包括类型(比如method、broadcast、attribute等)、参数、返回值。

创建HelloWorld.fidl文件:

package commonapi
​
interface HelloWorld {version {major 1 minor 0}method sayHello {in {String name}out {String message}}
}

fdepl文件描述了服务的部署信息,包括Service ID、Instance ID、Method ID、Event ID等。

创建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的全部功能。

用准备好的工具生成代码:

commonapi-core-generator-linux-x86_64 -sk ./fidl/HelloWorld.fidl
commonapi-someip-generator-linux-x86_64 ./fidl/HelloWorld.fdepl

在src-gen/v1/commonapi目录里,可以看到如下这些生成的代码文件:

万事俱备,可以开发应用程序咯~

对于服务端,主程序代码如下:

std::shared_ptr<CommonAPI::Runtime> runtime = CommonAPI::Runtime::get();
std::shared_ptr<HelloWorldStubImpl> myService = std::make_shared<HelloWorldStubImpl>();
// 注册服务
runtime->registerService("local", "test", myService);
std::cout << "Successfully Registered Service!" << std::endl;
while (true)
{std::cout << "Waiting for calls... (Abort with CTRL+C)" << std::endl;std::this_thread::sleep_for(std::chrono::seconds(30));
}
return 0;

其中,HelloWorldStubImpl是继承于工具生成的HelloWorldStubDefault:

class HelloWorldStubImpl: public v1_0::commonapi::HelloWorldStubDefault {
public:HelloWorldStubImpl();virtual ~HelloWorldStubImpl();virtual void sayHello(const std::shared_ptr<CommonAPI::ClientId> _client,std::string _name, sayHelloReply_t _return);
};

HelloWorldStubImpl实现了sayHello接口,正如fidl定义的,当客户端发送name,回复“Hello name !”:

void HelloWorldStubImpl::sayHello(const std::shared_ptr<CommonAPI::ClientId> _client,std::string _name, sayHelloReply_t _reply)
{std::stringstream messageStream;messageStream << "Hello " << _name << "!";std::cout << "sayHello('" << _name << "'): '" << messageStream.str() << "'\n";_reply(messageStream.str());
};

对于客户端,主程序如下:

std::shared_ptr < CommonAPI::Runtime > runtime = CommonAPI::Runtime::get();
std::shared_ptr<HelloWorldProxy<>> myProxy = runtime->buildProxy<HelloWorldProxy>("local", "test");
std::cout << "Checking availability!" << std::endl;
while (!myProxy->isAvailable()) usleep(10);
std::cout << "Available..." << std::endl;
CommonAPI::CallStatus callStatus;
std::string returnMessage;
// 调用sayHello服务接口
myProxy->sayHello("Bob", callStatus, returnMessage);
std::cout << "Got message: '" << returnMessage << "'\n";
return 0;

客户端不需要实现接口,直接使用工具生成的HelloWorldProxy就可以了。

编译运行的结果如下:

现在再看一下应该选择CommonAPI还是vsomeip呢?用vsomeip的话,依赖的东西少,Payload的打包和解析要自己写,工作量大,自由发挥的空间也大,用CommonAPI的话,依赖的东西多,环境搭建相对复杂,接口可以用IDL描述,这在SOA中非常有用,很多代码由工具生成,基本通信几乎不需要联调,主要的开发工作是实现服务的接口,相当于填充业务逻辑,工作量少,同时可以发挥的空间也小。很多事都是这样吧,获得便利的同时也会损失一些自由,如何选择还是要具体分析。

通过这个示例,我们看到使用RPC通信和上一篇中基于消息的通信是截然不同的编程体验,RPC让客户端可以像调用本地函数一样调用服务端的函数,很显然它们并不在同一个进程中,这是如何做到的呢?下面,我们结合一张经典的RPC原理框图(图片来源:https://www.cs.rutgers.edu/~pxk/417/notes/03-rpc.html)来看一下客户端的sayHello到底是怎么调到服务端的sayHello的:

1.client调用本地接口sayHello,HelloWorldProxy就是client的stub(桩),负责将sayHello的参数进行打包,组装成一个或者多个网络请求(这些取决于通信协议和序列化方式);

2.client的stub通过socket向server的stub,也叫skeleton(骨架),发送请求;

3.skeleton通过socket接收到请求;

4.请求消息被发送到skeleton,在这里就是HelloWorldStubDefault,负责将收到的请求拆包,取得client发送的参数;

5.HelloWorldStubDefault把参数发给了HelloWorldStubImpl的sayHello。

6.server在HelloWorldStubImpl的sayHello里处理了请求,通过sayHelloReply_t将返回值发给了HelloWorldStubDefault,它负责把返回值进行打包,组装成一个或者多个网络响应;

7.server的skeleton通过socket向client的stub发出响应;

8.stub通过socket接收到响应消息;

9.响应消息被发送到client的stub,也就是HelloWorldProxy,它负责将响应消息进行解析,取得server发送的参数;

10.client通过HelloWorldProxy的sayHello,得到了returnMessage。

至此,client完成了一次RPC调用~

可以看出,在RPC框架中,桩的实现原理是非常关键的,它屏蔽了网络通信的实现,让客户端可以像调用本地接口一样调用服务端提供的接口,而不用关心用的什么通信协议、序列化方式,以及所有的通信细节。CommonAPI的桩是由代码生成器根据IDL生成的,而在有的RPC框架里,还可以用动态代理的方式得到。

不知道在看这篇文章的你,是否用过RPC呢?反正我第一次接触RPC的时候,真的觉得很神奇,我明明写的是C++代码,却能调到别人写的Java代码里的函数?后来,我就一直对这一块很感兴趣,探索过很多RPC框架,今天就到这里吧,以后有机会可以慢慢唠嗑~

CommonAPI-SomeIP 使用相关推荐

  1. Linux C++ Commonapi环境搭建

    参考了以下文章: https://github.com/lixiaolia/commonapi_someip_demo https://blog.csdn.net/u010743397/article ...

  2. 01-死磕QNX someip

    1. vsomeip3.1.20版本  环境配置 export COMMONAPI_CONFIG=/etc/commonapi.ini export LD_LIBRARY_PATH=/sdcard/s ...

  3. CommonAPI 介绍

    image.png CommonAPI CommonAPI C++是用于开发分布式应用程序的标准C++ API规范,该分布式应用程序通过中间件进行进程间通信. CommonAPI C++依靠Franc ...

  4. SOMEIP环境搭建以及Demo详细介绍

    本文章主要基于开源的CommonAPI,CommonAPI-SOMEIP,VSomeIP来构建完整的SOMEIP协议规范实现 1.编译boost库 此处我选择1.68版本作为boost版本 boost ...

  5. 车联网SOMEIP应用总结

    1 汽车中的SOMEIP 1.1 IEEE规范 IEEE 802.3bw:100BASE-T1 IEEE 802.3bp:1000BASE-T1 IEEE 802.1Q:VLAN IEEE 802.1 ...

  6. 【车载以太网】【SOMEIP】Wireshark测试someip

    一. Wireshark SOMEIP plugin 1.1 插件安装 Wireshark插件目录:Help -> About Wireshark -> Folders/Plugins h ...

  7. CommonAPI使用例子-HelloWorld

    参考: https://at.projects.genivi.org/wiki/pages/viewpage.action?pageId=5472316   目录结构 存放文件 解释说明 mkdir ...

  8. 车载以太网之SomeIP协议

    一.SomeIP含义 SOME/IP ( Scalable service-Oriented MiddlewarE over IP):运行于IP之上的可伸缩的面向服务的中间件.它在系统中其实就是一个中 ...

  9. 车载以太网 - SomeIP - 详细解析 - 02

    对于介绍SomeIP协议,我还是想从最基础的协议解析来,所以今天还是先将SomeIP协议详解给大家列举一下,也方便大家在工作中如果不记得哪些信息随时可以查看学习,也算是留给我自己的笔记吧,毕竟确实容易 ...

  10. 车载以太网 - SomeIP - 总纲

    关于车载以太网中的SomeIP在网上也逐渐有越来越多的资料,讲的也是非常好:但是个人认为讲的泛,很难让初学者或者初入门者真正了解SomeIP到底是一个什么东西,以及它究竟在车载上有什么作用,本专栏会由 ...

最新文章

  1. 淘宝拼多多之争,从宏观的角度看拼多多是如何实现商业逆袭的?
  2. 卷积神经网络(CNN)反向传播算法
  3. Asp.net2.0工具包AjaxControlToolkit下载和安装
  4. Javascript 基础—变量 运算符
  5. sql server2008禁用远程连接
  6. javax.ws.rs.NotSupportedException: Cannot consume content type
  7. 2021年母婴行业洞察报告
  8. JavaScript高级程序设计读书笔记(一)
  9. 【前端性能优化】不用 setTimeout 实现防抖
  10. python类的继承代码_python--类的继承
  11. css实现数字钟表字体实现 fonts
  12. canvas设置lineWidth属性,出现线条被fill覆盖问题。
  13. 路由器计算机无法上网,连接路由器无法上网怎么回事_电脑连接路由器不能上网如何处理-win7之家...
  14. 车辆悬架刚度计算方法
  15. 走近图灵奖大师David Patterson开挂的人生
  16. JAVA视频网盘分享
  17. NATPort ForwardingPort Triggering
  18. 解决Android Studio 安装APK时device support,but apk only supports armeabi-v7 问题
  19. Telephone dialer
  20. 专题测试01·函数与极限【李艳芳全程班】

热门文章

  1. 音频系统POP音的原理和解决方法
  2. 致CSDN读者的一些话:感恩这十年的陪伴,不负遇见,短暂消失
  3. windows中office无法使用撤销键
  4. 1.【PPT】新建PPT文件、插入图片、插入文本框、添加形状、页面设置
  5. python创建excel并冻结首行
  6. amd linux raid,AMD RAID 安装指南.pdf
  7. Android 录屏+录音,原生代码,无需root权限,好用更好懂
  8. bin code led_LED混Bin生控制文件.pdf
  9. 【论文阅读】中医类药性分析:使用机器学习方法预测类药性
  10. 电瓶车换电柜的静电浪涌设计考虑