赞
踩
文档声明:
以下资料均属于本人在学习过程中产出的学习笔记,如果错误或者遗漏之处,请多多指正。并且该文档在后期会随着学习的深入不断补充完善。感谢各位的参考查看。
笔记资料仅供学习交流使用,转载请标明出处,谢谢配合。
如果存在相关知识点的遗漏,可以在评论区留言,看到后将在第一时间更新。
作者:Aliven888
这篇文章是对 vsomeip 官方 wiki 文档的一个翻译。属于个人学习开发笔记的一个记录。
SOME/IP 是 Scalable service-Oriented middleware over IP
的缩写。 该中间件专为典型的汽车用例而设计,并与 AUTOSAR 兼容(至少在有线格式级别上)。 可在 SOME/IP 上获得可公开访问的规范。 在这个 wiki 中,我们不想进一步深入探讨另一个中间件规范的原因,而是想对 SOME/IP 规范的基本结构及其开源实现 vsomeip 给出一个粗略的概述,而不要求任何完整性。
让我们从 SOME/IP 规范的三个主要部分开始:
原则上,SOME/IP 通信由设备或订阅者之间通过 IP 发送的消息组成。 详见如下图示:
这里你会看到两个设备(A 和 B); 设备 A 向 B 发送一条 SOME/IP 消息,并收到一条回复消息。
底层传输协议可以是 TCP 或 UDP; 对于消息本身,这没有什么区别。
现在我们假设设备 B 上正在运行一个服务,该服务提供了一个由该消息从设备 A 调用的函数,而返回的消息就是答案。
SOME/IP 的消息由两部分组成: header
和 payload
。
在图片中,您可以看到 header
主要由标识符组成:
我们可以看到,对于客户端已订阅的事件,正常函数的调用和通知消息都有“请求”和“响应”。 错误报告为正常响应或通知,并且会返回错误代码。
payload 包含序列化数据。 如上图示的传输数据结构,只有基本数据类型的嵌套结构下的简单序列化。 在这种情况下,结构元素只是被展平,然后它们被一个接一个地写入 payload 中。
在本节中,主要有两点很重要,现在将对其进行描述:
如上所述,底层传输协议可以是 UDP 或 TCP。 在 UDP 情况下,SOME/IP 消息没有分段; 一个 UDP 数据包中可能包含多条消息,但一条消息的长度不能超过 UDP 数据包的长度(最多 1400 字节)。 更大的消息必须通过 TCP 传输。 在这种情况下,使用了 TCP 的所有健壮性特征。 如果 TCP 流中发生同步错误,SOME/IP 规范允许所谓的 magic cookies
以便再次找到下一条消息的开头。
请注意,必须实例化服务接口,并且因为可能存在同一接口的多个实例,所以必须为定义的实例添加一个附加标识符(instance ID)。 但是,instance ID 不是 SOME/IP 消息的标头的一部分。 实例通过传输协议的端口号识别; 这意味着不可能在同一端口上提供同一接口的多个实例。
现在请看下图,它显示了基本的 SOME/IP 通信模式:
除了用于远程过程调用的标准 请求-响应
机制之外,还有用于事件的 发布-订阅
模式。 请注意,SOME/IP 协议中的事件总是分组在一个事件组中; 因此只能订阅事件组而不是事件本身。
SOME/IP 规范也有 fields
; 在这种情况下,setter/getter
方法遵循 请求-响应
模式,并且更改的通知消息是事件。 订阅本身是通过 SOME/IP 服务发现完成的。
SOME/IP
服务发现用于定位服务实例并检测服务实例是否正在运行以及实现发布/订阅处理。 这主要是通过所谓的报价消息来完成的; 同时也意味着每个设备都广播(多播)消息,并在广播的消息中包含该设备提供的所有服务信息。
SOME/IP
SD 消息通过 UDP 发送。
如果客户端应用程序需要服务但目前没有提供,那么也可以发送查找消息(find messages)
。 其他 SOME/IP
SD 消息可用于发布或订阅事件组。
SOME/IP SD 消息的结构显示如下:
这应该足够开始了。 更多细节将在后面的示例中讨论,或者可以在说明书中阅读。
在我们开始实现介绍示例之前,让我们简要了解一下 SOME/IP
的 GENIVI
实现的基本结构,即vsomeip
。
如图所示,vsomeip
不仅涵盖了设备之间的 SOME/IP
通信(外部通信),还涵盖了内部进程间通信。 两个设备通过所谓的通信端点进行通信,这些端点将使用的传输协议(TCP 或 UDP)
及其参数确定为端口号或其他参数。 所有这些参数都是可以在 vsomeip
配置文件中设置的配置参数(json 文件,请参阅 vsomeip 用户指南)
。 内部通信是通过本地端点完成的,这些端点由 unix
域套接字使用Boost.Asio
库实现。 由于这种内部通信不是通过中央组件(例如,像 D-Bus 守护程序)路由的,因此它非常快。
vsomeip
中央路由管理器仅在必须将消息发送到外部设备时才获取消息,并且他分发来自外部的消息。 每台设备只有一个路由管理器; 如果未配置任何内容,则第一个运行的 vsomeip
应用程序也会启动路由管理器。
❗️ vsomeip
没有实现数据结构的序列化! CommonAPI
的 SOME/IP
绑定涵盖了这一点。vsomeip
仅涵盖 SOME/IP
协议和服务发现。
现在这是对 SOME/IP
和 vsomeip
的非常、非常简短的概述。 但是对于第一次开始就足够了; 更多细节在示例中直接解释。
如前所述,vsomeip
需要 Boost.Asio
库,因此请确保您已在系统上安装了 BOOST(至少 1.55 版)
。 成功安装 Boost
后,您可以像往常一样轻松构建 vsomeip
:
$ cd vsomeip
<.>/vsomeip$ mkdir build
<.>/vsomeip$ cd build
<.>/vsomeip/build$ cmake ..
<.>/vsomeip/build$ make
This works, but in order to avoid some special problems afterwards I recommend to add at least one parameter to your CMake call:
虽然这样就搞定了,但为了避免之后出现一些特殊问题,我建议在您的 CMake 调用中添加至少一个参数:
> cmake -DENABLE_SIGNAL_HANDLING=1 ..
此参数确保您可以毫无问题地终止您的 vsomeip 应用程序(否则可能是当您使用 Ctrl-C 停止应用程序时,共享内存段 /dev/shm/vsomeip 未正确删除)
。
创建第一个 vsomeip
程序,我们称它为 service-example
:
/*service-example.cpp*/
#include <vsomeip/vsomeip.hpp>
std::shared_ptr< vsomeip::application > app;
int main() {
app = vsomeip::runtime::get()->create_application("World");
app->init();
app->start();
}
这很容易:您必须首先创建一个应用程序对象,然后初始化并启动它。 创建 vsomeip
应用程序后必须首先调用 init 方法,并执行以下步骤对其进行初始化:
The start method has to be called after init in order to start the message processing. The received messages are processed via sockets and registered callbacks are used to pass them to the user application.
为了启动消息处理,必须在 init 之后调用 start
方法。 接收到的消息通过套接字进行处理,并使用注册的回调将它们传递给用户应用程序。
READY
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。