vsomeip环境搭建+双机通讯
ubuntu系统下的vsomeip环境搭建
一种可运行环境配置
vsomeip 3.3.8
cmake 3.27
boost 1.78
- 下载源码
去gitcode/github上下载源码
vsomeip源码下载
或者直接执行
git clone https://gitcode.net/mirrors/COVESA/vsomeip.git
可以得到最新版本的vsomeip源码。 - 安装依赖项
-
cmake
安装
用sudo apt-get install cmake
安装的cmake的版本较老,已经不适用。
需要我们去官网上找较高版本的cmake进行下载安装。
cmake官网地址
可以自行选择下载一个较新的版本。
也可以直接从github上克隆最新版,目前是3.27。
git clone https://github.com/Kitware/CMake.git
下载后打开文件夹,按步骤执行命令./bootstrap
make
sudo make install
make过程大概需要十几二十分钟
上述全部执行完
执行cmake -version
能查到版本信息就说明安装成功了。
卸载
回到文件夹目录下,会发现有一个install_manifest.txt文件,执行命令
cat install_manifest.txt | sudo xargs rm
就可以完成卸载。
此时再执行cmake -version就查不到版本信息了。 -
boost库
安装
同样的,用sudo apt-get install libboost
安装的boost版本较老,不适用于一些较高版本的vsomeip(但适用于vsomeip3.3.0版本,应该是可以适配vsomeip3.3.0及以下版本),如果使用较高版本的vsomeip,比如最新版,需要自行下载安装较高版本的boost。
去官网
boost下载
下载boost_1_78_0.tar.gz
解压,进到文件夹,依次执行./bootstrap.sh
./b2
sudo ./b2 install
卸载
依次执行sudo rm -f /usr/local/lib/libboost*
sudo rm -rf /usr/local/include/boost
sudo rm -rf /usr/local/lib/cmake/boost* -
其他依赖
其他依赖asciidoc、source-highlight、doxygen、graphviz安装比较简单,直接执行以下命令
sudo apt-get install asciidoc source-highlight doxygen graphviz
-
搭建编译环境
mkdir build
cd build
cmake …
make
sudo make install
至此,vsomeip环境配置完成。
跑通helloworld程序
找到vsomeip根目录下的example中的helloworld文件夹,进入可以看到一个readme文档,根据提示依次执行命令
mkdir build
cd build
cmake ..
make
因为是本机通讯,其实不改配置文件也可以,直接执行
VSOMEIP_CONFIGURATION=../helloworld-local.json \
VSOMEIP_APPLICATION_NAME=hello_world_service \
./hello_world_service
VSOMEIP_CONFIGURATION=../helloworld-local.json \
VSOMEIP_APPLICATION_NAME=hello_world_client \
./hello_world_client
此时应该可以看到和readme文档一样的expected输出。
如果报错:
libboost_thread.so.xxx.xxx.xxx: cannot open shared object file: No such file or directory
执行
sudo ldconfig
即可。
跑通request-sample&&response-sample和notify-sample&&subscribe-sample
本机通讯
进入根目录刚才build的文件夹内,找到examples,进入,执行命令
make
会得到四个可执行文件,分别是request-sample&&response-sample,notify-sample&&subscribe-sample。
回到根目录,直接进入examples,查看readme文件。
可以看到我们可以回到可执行文件目录,执行
请求/响应:
env VSOMEIP_CONFIGURATION=../../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=client-sample ./request-sample
env VSOMEIP_CONFIGURATION=../../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=service-sample ./response-sample
发布/订阅:
env VSOMEIP_CONFIGURATION=../../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=client-sample ./subscribe-sample
env VSOMEIP_CONFIGURATION=../../config/vsomeip-local.json VSOMEIP_APPLICATION_NAME=service-sample ./notify-sample
以此来实现请求响应或发布订阅模式。
上述实现了两种模式的本机通讯。
双机通讯
配置双机通讯环境
- 让两台主机都加入组播
route add -net 224.0.0.0/4 dev eth0
- 编辑配置文件
可以copy一份config里的vsomeip-local.json进行修改,放到/build/example
目录下。
修改的内容主要为:
- 修改unicast为本机ip。
- 修改routing为本机运行的application的名字,即和配置文件中的application的name匹配上,和程序运行时设置的环境变量VSOMEIP_APPLICATION_NAME也需要匹配上。
运行程序
实现发布/订阅,执行
VSOMEIP_CONFIGURATION=./client.json \
VSOMEIP_APPLICATION_NAME=Hello \
./subscribe-sample
VSOMEIP_CONFIGURATION=./service.json \
VSOMEIP_APPLICATION_NAME=World \
./notify-sample
实现请求/响应改一下文件名就行。
至此,实现双机通讯。
配置文件中一些参数的说明
"unicast"
:本机ip地址
"logging"
:日志相关
"level"
: 默认debug,设置成error可以屏蔽掉除了error外的打印
"applications"
:程序中的application设置"name"
:application名,必须和环境变量对应上"id"
:applicationID
services
:
service
:serviceIDinstance
:instanceIDunreliable
:表明是UDP传输,对应的reliable
是TCP传输,这里的值表示UDP传输端口号,是service必须要有的events
:事件,包括eventID和一些其他配置eventgroups
:事件组,包括事件组ID、事件组包含的eventID和一些其他配置
routing
:充当路由角色的application
的名称,如果没有指定,则本机第一个启动的vsomeip程序充当路由角色。单机通讯时可以任意指定client还是server端充当路由角色,双机通讯时则指定为本机的某个application
的名字。
service-discovery
:服务发现相关
enable
:服务发现模块是否可用multicast
:服务发现的组播地址port
:收发sd消息的端口protocol
:组播协议initial_delay_min
:初始延迟最小值,用于调整服务实例启动后首次发布服务信息的时间initial_delay-max
:初始延迟最大值,同上repetitions_base_delay
:每次重复广播sd消息的基础延迟时间。首次广播sd消息,会先重复广播一定次数,之后再进入循环广播。repetitions_max
:首次广播sd消息时的最大重发次数ttl
:sd消息的生存时间cyclic_offer_delay
:循环offer的时间间隔request_response_delay
:请求响应延迟时间,控制响应速度
自定义开发
service端
配置信息
service端的app的名字和app的id需要写入配置文件service.json
中。以LaneChange为例,例如:
"applications" :
[
{
"name" : "LaneChange_SP",
"id" : "0x0202"
}
]
启动程序时需要把环境变量设置为相同的名字。
需要明确service端的service id,service instance以及udp传输的端口号,即对应词条unreliable,这些信息必须写入配置文件中。例如:
"services" :
[
{
"service" : "0x301C",
"instance" : "0x0001",
"unreliable" : "33529"
}
]
将service id和instance id写入sample-ids.hpp
头文件中,可以根据其不同的服务内容为其命名,明确各个id可以提供的服务内容。例如:
#define LANE_CHANGE_SERVICE_ID 0x301C
#define LANE_CHANGE_INSTANCE_ID 0x0001
RR模式需要相应的method id,notification模式需要相应的event id和eventgroup id。这些需要写入头文件中,可以根据其服务模式为其命名。这些不需要写入配置文件中。例如:
#define LANE_CHANGE_EVENT_ID 0x8001
#define LANE_CHANGE_EVENTGROUP_ID 0x0001
#define LANE_CHANGE_METHOD_ID 0x0001
service.cpp
程序
程序中的逻辑时序:
application初始化 —— app_->init()
application初始化状态 —— app_->register_state_handler
消息接收回调 —— app_->register_message_handler,为指定的method或event注册处理程序。用户应用程序必须调用此方法来为其注册回调。例如:
app_->register_message_handler(
LANE_CHANGE_SERVICE_ID,
LANE_CHANGE_INSTANCE_ID,
LANE_CHANGE_METHOD_ID,
std::bind(&service_sample::on_get, this,
std::placeholders::_1));
这里的on_get函数就是自定义的接收到源消息后的处理操作。
注:每个服务(SERVICE)、实例(INSTANCE)、方法/事件(METHOD)组合只能注册一个处理程序。
提供事件源(服务端) —— app_->offer_event,参数列表填入提供事件的service id,instance id,event id和group id。例如:
std::set<vsomeip::eventgroup_t> its_groups;
its_groups.insert(LANE_CHANGE_EVENTGROUP_ID);
app_->offer_event(
LANE_CHANGE_SERVICE_ID,
LANE_CHANGE_INSTANCE_ID,
LANE_CHANGE_EVENT_ID,
its_groups,
vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(),
false, true, nullptr, vsomeip::reliability_type_e::RT_UNKNOWN);
切换线程到运行模式(run)
同时,app_->start。
提供服务源(服务端) —— app_->offer_service,参数列表填入需要offer的service id和instance id。例如:
app_->offer_service(LANE_CHANGE_SERVICE_ID, LANE_CHANGE_INSTANCE_ID);
然后就是设定stop_offer的触发条件,代码里是用时间控制的。
之后service就循环进行offer了,主要就是通过app_->register_message_handler注册的处理程序来对一些指定方法或事件(method id)进行响应(执行自定义操作)。
client端
配置信息
client端的配置文件不需要配置service id和端口这类信息,只需要配置好client端的app名字和id即可。在头文件内写入所需要的服务信息,用于request,一般和service端共享同一个头文件就可以。
client.cpp
程序
程序中的逻辑时序:
application初始化 —— app_->init()
application初始化状态 —— app_->register_state_handler
消息接收回调 —— app_->register_message_handler
服务实例的可用状态 —— app_->register_availability_handler
请求事件并且订阅(客户端) —— app_->request_event,这里明确请求的信息,包括提供所需要事件源的service id,service instance,event id,以及group id。订阅信息包括所需事件源的service id,service instance,group id,因为是以事件组的方式订阅,例如:
std::set<vsomeip::eventgroup_t> its_groups;
its_groups.insert(LANE_CHANGE_EVENTGROUP_ID);
app_->request_event(
LANE_CHANGE_SERVICE_ID,
LANE_CHANGE_INSTANCE_ID,
LANE_CHANGE_EVENT_ID,
its_groups,
vsomeip::event_type_e::ET_FIELD);
订阅事件组(客户端) —— app_->subscibe,订阅信息包括所需事件源的service id,service instance,group id,因为是以事件组的方式订阅,例如:
app_->subscribe(LANE_CHANGE_SERVICE_ID, LANE_CHANGE_INSTANCE_ID, LANE_CHANGE_EVENTGROUP_ID);
之后app_->start。
如果之前app注册成功,则应该请求服务,需要包含请求服务的service id,service instance,例如:
app_->request_service(LANE_CHANGE_SERVICE_ID, LANE_CHANGE_INSTANCE_ID);
然后就是等待offer_service和offer_event,一旦接收到相应的消息,message和availability这两个回调函数会执行相应的自定义操作。