VSOMEIP双机通信
介绍下demo怎么写的还有双机通信怎么实现
编写配置环境
由于VSOMEIP是个库,所以和其他的库一样用就行了。
首先创建demo目录
这里创建的是vsomeip_demo文件夹
里面创建个server端的cpp和client端的cpp,这里只是编译,不用在两个电脑上分别创建。
建个build,用于存放json配置文件,和CmakeList生成的Makefile等东西。
其中CakeList.txt就是cmake的文件,代码如下:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
set (CMAKE_CXX_FLAGS "-g -std=c++0x")
set (vsomeip_DIR /home/xiong/work/VSOMEIP/source/vsomeip-master)
set (Boost_INCLUDE_DIR /home/xiong/work/VSOMEIP/install/boost_1_72_0/include)
find_package (vsomeip3 REQUIRED)
find_package( Boost 1.72 COMPONENTS system thread log REQUIRED )
include_directories (
${Boost_INCLUDE_DIR}
${VSOMEIP_INCLUDE_DIRS}
)
add_executable(service service.cpp)
add_executable(client client.cpp)
target_link_libraries(service vsomeip3 ${Boost_LIBRARIES})
target_link_libraries(client vsomeip3 ${Boost_LIBRARIES})
没多少代码,就是添加几个库的路径,添加源文件,能过够让编译器找到对应的库和源文件,这个路径需要改成对应电脑的路径。
然后再build里面编译cmake …
结果如下:
这里auto.sh和vsoemip.json是为了配置放的,其他都是cmake生成的。
然后make一下:
然后就生成了server和client两个可执行文件
现在运行./server的话会出现:
其根本原因是没有库的路径到指定环境变量LD_LIBRARY_PATH中,我又不想永久写到配置文件中,本来想打算写个sh添加以下,后面发现sh好像export不了,没办法只能把sh里面的东西复制出来到终端执行:
如果想添加到配置文件的话把LD_LIBRARY_PATH添加以下就好了,添加完之后就能正常运行了。
双机通信
双机通信就配置以下vsomeip.json文件就好了,这里我用的是单播进行的通信,这个是server端的,另一台电脑上IP反过来写就行,然后APP的名字和routing名字这些配置改一下就行。
{
"unicast" : "192.168.0.10",
"applications" :
[
{
"name" : "Hello",
"id" : "0x1313"
}
],
"routing" : "Hello",
"service-discovery" :
{
"enable" : "true",
"mode" : "unicast",
"unicast" : [
"192.168.0.11"
],
"multicast" : "224.224.224.245",
"port" : "30490",
"protocol" : "udp",
"initial_delay_min" : "10",
"initial_delay_max" : "100",
"repetitions_base_delay" : "200",
"repetitions_max" : "3",
"ttl" : "3",
"cyclic_offer_delay" : "2000",
"request_response_delay" : "1500"
}
}
配置文件没啥好讲的就是配置以下自己的ip,配置一下app的ID和name,然后配一下SD的参数,设成单播,至于SD报文的重复的base时间这些参数就按照这个设置就行,改不改的不要太离谱就行。
配完make一下生成的两个可执行文件分别放到对应IP的两台主机上进行运行,就可以双机通信了。
代码详解
server.cpp
#include <iomanip>
#include <iostream>
#include <sstream>
#include <vsomeip/vsomeip.hpp>
#define SAMPLE_SERVICE_ID 0x1234
#define SAMPLE_INSTANCE_ID 0x5678
#define SAMPLE_METHOD_ID 0x0421
std::shared_ptr<vsomeip::application> app;
void on_message(const std::shared_ptr<vsomeip::message> &_request) {
std::cout << "asdfghjkl" << std::endl;
std::shared_ptr<vsomeip::payload> its_payload = _request->get_payload();
vsomeip::length_t l = its_payload->get_length();
// Get payload
std::stringstream ss;
for (vsomeip::length_t i=0; i<l; i++) {
ss << std::setw(2) << std::setfill('0') << std::hex
<< (int)*(its_payload->get_data()+i) << " ";
}
std::cout << "SERVICE: Received message with Client/Session ["
<< std::setw(4) << std::setfill('0') << std::hex << _request->get_client() << "/"
<< std::setw(4) << std::setfill('0') << std::hex << _request->get_session() << "] "
<< ss.str() << std::endl;
// Create response
std::shared_ptr<vsomeip::message> its_response = vsomeip::runtime::get()->create_response(_request);
its_payload = vsomeip::runtime::get()->create_payload();
std::vector<vsomeip::byte_t> its_payload_data;
for (int i=9; i>=0; i--) {
its_payload_data.push_back(i % 256);
}
its_payload->set_data(its_payload_data);
its_response->set_payload(its_payload);
app->send(its_response);
}
int main() {
app = vsomeip::runtime::get()->create_application("World");
app->init();
app->register_message_handler(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_METHOD_ID, on_message);
app->offer_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
app->start();
}
没有helloworld那么麻烦,在主函数里面就是注册了一个app,然后init一下,注册一个收到request的回调函数on_message,然后就offer_service跟start,就开启各种线程服务启动了。
client.cpp
#include <iomanip>
#include <iostream>
#include <sstream>
#include <condition_variable>
#include <thread>
#include <vsomeip/vsomeip.hpp>
#define SAMPLE_SERVICE_ID 0x1234
#define SAMPLE_INSTANCE_ID 0x5678
#define SAMPLE_METHOD_ID 0x0421
std::shared_ptr< vsomeip::application > app;
std::mutex mutex;
std::condition_variable condition;
void run() {
std::unique_lock<std::mutex> its_lock(mutex);
condition.wait(its_lock);
std::shared_ptr< vsomeip::message > request;
request = vsomeip::runtime::get()->create_request();
request->set_service(SAMPLE_SERVICE_ID);
request->set_instance(SAMPLE_INSTANCE_ID);
request->set_method(SAMPLE_METHOD_ID);
std::shared_ptr< vsomeip::payload > its_payload = vsomeip::runtime::get()->create_payload();
std::vector< vsomeip::byte_t > its_payload_data;
for (vsomeip::byte_t i=0; i<10; i++) {
its_payload_data.push_back(i % 256);
}
its_payload->set_data(its_payload_data);
request->set_payload(its_payload);
app->send(request);
}
void on_message(const std::shared_ptr<vsomeip::message> &_response) {
std::cout << "sdsdsdsdsdsdsdsdsdsds" << std::endl;
std::shared_ptr<vsomeip::payload> its_payload = _response->get_payload();
vsomeip::length_t l = its_payload->get_length();
// Get payload
std::stringstream ss;
for (vsomeip::length_t i=0; i<l; i++) {
ss << std::setw(2) << std::setfill('0') << std::hex
<< (int)*(its_payload->get_data()+i) << " ";
}
std::cout << "CLIENT: Received message with Client/Session ["
<< std::setw(4) << std::setfill('0') << std::hex << _response->get_client() << "/"
<< std::setw(4) << std::setfill('0') << std::hex << _response->get_session() << "] "
<< ss.str() << std::endl;
}
void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) {
std::cout << "CLIENT: Service ["
<< std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance
<< "] is "
<< (_is_available ? "available." : "NOT available.")
<< std::endl;
condition.notify_one();
}
int main() {
app = vsomeip::runtime::get()->create_application("Hello");
app->init();
app->register_availability_handler(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, on_availability);
app->request_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
app->register_message_handler(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_METHOD_ID, on_message);
std::thread sender(run);
app->start();
}
client.cpp流程大体和server端一样,就是多注册了几个函数用于request服务,检测服务是否可用等函数,然后开了个线程来发送request数据,最后start,实现一个SOMEIP中最简单的request/response交互流程,有时间的可以抓包看一下报文。
总结
最近出差多没时间总结,现在把之前双机通信的案例总结一下,后面关于多播的就不写了都是一样的。