ubuntu18.04 vsomeip的编译及使用
1、概述
vsomeip (Vehicle SOME/IP) 是 GENIVI 联盟(现并入 COVESA - Connected Vehicle Systems Alliance)推出的一个开源项目,它实现了 SOME/IP (Scalable service-Oriented MiddlewarE over IP) 协议。这是一个专为汽车和嵌入式系统设计的通信协议,用于支持服务发现、远程过程调用(RPC)和事件通知等功能。
下面是关于 vsomeip 的核心介绍,我用一个表格来汇总其主要特性:
特性维度 | 说明 |
---|---|
核心功能 | 实现了 SOME/IP 协议及其服务发现(Service Discovery)机制 |
通信模式 | 支持请求/响应(Request/Response)、发布/订阅(Publish/Subscribe)等 |
传输协议 | 支持 TCP 和 UDP |
内部通信 | 通过 Unix 域套接字实现同一设备内进程间的高速通信 |
路由管理 | 中央路由管理器(Routing Manager)负责消息的路由和分发 |
序列化 | vsomeip 自身不处理复杂数据结构的序列化,此部分通常由 CommonAPI 等工具完成 |
主要依赖 | Boost 库(特别是 Asio、Thread、System) |
构建系统 | CMake |
配置方式 | 使用 JSON 格式的配置文件 |
应用领域 | 车载信息娱乐系统(IVI)、车身控制、自动驾驶辅助系统等车载网络通信 |
2、 基本工作原理
vsomeip 的工作核心是 服务(Service) 和 实例(Instance)。每个服务都有一个唯一的 Service ID,一个服务可以有多个实例(Instance ID)。通信双方(服务提供者 Consumer)通过 Service ID 和 Instance ID 来识别和定位服务。
其工作流程通常包含:
1.服务注册与发现 (Service Discovery): 服务提供者启动后,会通过 offer_service
方法宣告其提供的服务。客户端则通过request_service
和注册可用性回调函数来发现并监控服务的状态变化。
2.消息传递: 建立连接后,双方通过 消息处理程序(Message Handler) 来接收和处理请求或响应。服务端需为特定的 Method ID 注册消息处理器,客户端则发送请求并等待响应。
3、编译
vsomeip依赖Boost,因此我们需要先编译和安装Boost:
编译步骤:点击跳转
接着,编译和安装vsomeip:
下载: github下载、csdn下载
cmake -DCMAKE_INSTALL_PREFIX:PATH=/home/gui/gui/build -DBOOST_ROOT=/home/gui/gui/build -DBoost_DIR=/home/gui/gui/build -DENABLE_SIGNAL_HANDLING=1 -DDIAGNOSIS_ADDRESS=0x10 ..
make -j$(nproc)
sudo make install
避坑:
vsomeip-master/implementation/endpoints/src/asio_socket_factory.cpp:27:2: error: extra ‘;’ [-Werror=pedantic]};
解决:
- 错误位置在asio_socket_factory.cpp代码最后一行的
};
,这里多了一个分号,将其删掉便可!
4、demo
//server.cpp
#include <vsomeip/vsomeip.hpp>
#include <chrono>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <iomanip>
#include <signal.h>
#include <cstdio>
#define LOG_INF(...) std::fprintf(stdout, __VA_ARGS__), std::fprintf(stdout, "\n")
#define LOG_ERR(...) std::fprintf(stderr, __VA_ARGS__), std::fprintf(stderr, "\n")// 全局常量定义
static vsomeip::service_t service_id = 0x1111;
static vsomeip::instance_t service_instance_id = 0x2222;
static vsomeip::method_t service_method_id = 0x3333;// 全局变量 - 替代类的成员变量
static std::shared_ptr<vsomeip::runtime> rtm_;
static std::shared_ptr<vsomeip::application> app_;
static bool stop_ = false;
static std::mutex mutex_;
static std::condition_variable condition_;
static std::thread stop_thread_;// 函数声明
bool init();
void start();
void stop();
void terminate();
void on_state_cbk(vsomeip::state_type_e _state);
void on_message_cbk(const std::shared_ptr<vsomeip::message>& _request);// 初始化函数
bool init()
{// 获取vSomeIP运行时并创建应用rtm_ = vsomeip::runtime::get();app_ = rtm_->create_application();// 初始化应用if (!app_->init()) {LOG_ERR("Couldn't initialize application");return false;}// 注册消息处理器回调app_->register_message_handler(service_id, service_instance_id, service_method_id,on_message_cbk);// 注册状态处理器app_->register_state_handler(on_state_cbk);return true;
}// 启动函数
void start()
{// 启动应用app_->start();
}// 停止线程函数
void stop()
{std::unique_lock<std::mutex> its_lock(mutex_);while (!stop_) {condition_.wait(its_lock);}std::this_thread::sleep_for(std::chrono::seconds(5));// 停止提供服务app_->stop_offer_service(service_id, service_instance_id);// 注销状态处理器app_->unregister_state_handler();// 注销消息处理器app_->unregister_message_handler(service_id, service_instance_id, service_method_id);// 关闭应用app_->stop();
}// 终止函数
void terminate()
{std::lock_guard<std::mutex> its_lock(mutex_);stop_ = true;condition_.notify_one();
}// 状态回调函数
void on_state_cbk(vsomeip::state_type_e _state)
{if (_state == vsomeip::state_type_e::ST_REGISTERED) {// 注册成功后提供服务app_->offer_service(service_id, service_instance_id);}
}// 消息回调函数
void on_message_cbk(const std::shared_ptr<vsomeip::message>& _request)
{// 打印接收到的数据if (_request && _request->get_payload()) {const vsomeip::payload* payload = _request->get_payload().get();std::string received_data(reinterpret_cast<const char*>(payload->get_data()), payload->get_length());LOG_INF("Received data from client (length: %zu bytes):", payload->get_length());LOG_INF(" String: %s", received_data.c_str());// 以十六进制格式打印数据LOG_INF(" Hex: ");for (uint32_t i = 0; i < payload->get_length(); ++i) {printf("0x%02X ", payload->get_data()[i]);}printf("\n");}// 创建响应std::shared_ptr<vsomeip::message> resp = rtm_->create_response(_request);// 构造返回字符串std::string str("Hello ");str.append(reinterpret_cast<const char*>(_request->get_payload()->get_data()), 0, _request->get_payload()->get_length());// 创建返回负载std::shared_ptr<vsomeip::payload> resp_pl = rtm_->create_payload();std::vector<vsomeip::byte_t> pl_data(str.begin(), str.end());resp_pl->set_data(pl_data);resp->set_payload(resp_pl);// 打印发送的数据LOG_INF("Sending response to client (length: %zu bytes):", str.length());LOG_INF(" String: %s", str.c_str());// 以十六进制格式打印发送的数据LOG_INF(" Hex: ");for (char c : str) {printf("0x%02X ", static_cast<unsigned char>(c));}printf("\n");// 发送响应app_->send(resp);// 完成后终止terminate();
}int main(int argc, char** argv)
{// 初始化停止线程stop_thread_ = std::thread(stop);// 初始化并启动服务if (init()) {start();// 等待停止线程结束if (stop_thread_.joinable()) {stop_thread_.join();}return 0;} else {return 1;}
}
//client.cpp
#include <vsomeip/vsomeip.hpp>#include <cstdio>
#define LOG_INF(...) fprintf(stdout, __VA_ARGS__), fprintf(stdout, "\n")
#define LOG_ERR(...) fprintf(stderr, __VA_ARGS__), fprintf(stderr, "\n")// 全局变量代替类的成员变量
static vsomeip::service_t service_id = 0x1111;
static vsomeip::instance_t service_instance_id = 0x2222;
static vsomeip::method_t service_method_id = 0x3333;
static std::shared_ptr<vsomeip::runtime> rtm_;
static std::shared_ptr<vsomeip::application> app_;
static bool is_running = false;void stop();
// 状态回调函数
void on_state_cbk(vsomeip::state_type_e _state)
{if (_state == vsomeip::state_type_e::ST_REGISTERED) {// 注册成功后请求服务app_->request_service(service_id, service_instance_id);}
}// 可用性回调函数
void on_availability_cbk(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available)
{// 检查是否是我们需要的服务if (service_id == _service && service_instance_id == _instance && _is_available) {// 服务可用,发送请求std::shared_ptr<vsomeip::message> rq = rtm_->create_request();rq->set_service(service_id);rq->set_instance(service_instance_id);rq->set_method(service_method_id);// 创建并设置 payloadstd::shared_ptr<vsomeip::payload> pl = rtm_->create_payload();std::string str("World");std::vector<vsomeip::byte_t> pl_data(std::begin(str), std::end(str));pl->set_data(pl_data);rq->set_payload(pl);LOG_INF("Sending: %s", str.c_str());app_->send(rq);}
}// 消息回调函数
void on_message_cbk(const std::shared_ptr<vsomeip::message>& _response)
{if (service_id == _response->get_service() && service_instance_id == _response->get_instance()&& vsomeip::message_type_e::MT_RESPONSE == _response->get_message_type()&& vsomeip::return_code_e::E_OK == _response->get_return_code()) {// 获取并打印响应 payloadstd::shared_ptr<vsomeip::payload> pl = _response->get_payload();std::string resp = std::string(reinterpret_cast<const char*>(pl->get_data()), 0, pl->get_length());LOG_INF("Received: %s", resp.c_str());stop();}
}// 初始化函数
bool init()
{// 获取 runtime 并创建应用rtm_ = vsomeip::runtime::get();app_ = rtm_->create_application();// 初始化应用if (!app_->init()) {LOG_ERR("Couldn't initialize application");return false;}// 注册状态回调app_->register_state_handler(on_state_cbk);// 注册消息处理回调app_->register_message_handler(vsomeip::ANY_SERVICE, service_instance_id, vsomeip::ANY_METHOD, on_message_cbk);// 注册可用性回调app_->register_availability_handler(service_id, service_instance_id, on_availability_cbk);return true;
}// 启动函数
void start()
{is_running = true;app_->start();is_running = false;
}// 停止函数
void stop()
{if (app_) {// 注销状态处理器app_->unregister_state_handler();// 注销消息处理器app_->unregister_message_handler(vsomeip::ANY_SERVICE, service_instance_id, vsomeip::ANY_METHOD);// 清除所有处理器app_->clear_all_handler();// 释放服务app_->release_service(service_id, service_instance_id);// 停止应用app_->stop();}is_running = false;
}int main(int argc, char** argv)
{if (init()) {start();return 0;} else {return 1;}
}
//helloworld-local.json
{"unicast": "127.0.0.1","logging": {"level": "debug","console": "false"},"applications": [{"name": "server","id": "0x4444"},{"name": "client","id": "0x5555"}],"services": [{"service": "0x1111","instance": "0x2222","unreliable": "30509"}],"routing": "server","service-discovery": {"enable": "false"}
}
//1.sh 编译脚本
#!/bin/bash# 编译选项
CXX=g++
CXXFLAGS="-std=c++17 -Wall -Wextra -I."
LDFLAGS="-lvsomeip3 -lpthread"# 源文件和目标文件
SERVICE_SRC="./server.cpp"
CLIENT_SRC="./client.cpp"
SERVICE_TARGET="server"
CLIENT_TARGET="client"# 检查vsomeip是否安装
if ! pkg-config --exists vsomeip3; thenecho "错误: 未找到vsomeip3库。请先安装vsomeip。"exit 1
fi# 添加pkg-config提供的编译和链接选项
CXXFLAGS="$CXXFLAGS $(pkg-config --cflags vsomeip3)"
LDFLAGS="$LDFLAGS $(pkg-config --libs vsomeip3)"# 编译服务端
echo "编译服务端..."
$CXX $CXXFLAGS -o $SERVICE_TARGET $SERVICE_SRC $LDFLAGS# 检查编译是否成功
if [ $? -ne 0 ]; thenecho "服务端编译失败"exit 1
fi# 编译客户端
echo "编译客户端..."
$CXX $CXXFLAGS -o $CLIENT_TARGET $CLIENT_SRC $LDFLAGS# 检查编译是否成功
if [ $? -ne 0 ]; thenecho "客户端编译失败"exit 1
fiecho "编译成功!生成了以下可执行文件:"
echo " - $SERVICE_TARGET"
echo " - $CLIENT_TARGET"
觉得有帮助的话,打赏一下呗。。
需要商务合作(定制程序)的欢迎私信!!