4. SOME/IP服务端实现
任务目标
在DoIP(Diagnostic over IP)之上实现一个SOME/IP服务端,对外提供加法计算服务。客户端发送两个32位整数,服务端计算其和并返回结果。本案例聚焦SOME/IP服务端的核心实现:服务发现(OfferService)与请求/响应处理。
环境与依赖
- 操作系统:Linux(Ubuntu 20.04+)或Windows(WSL2)
- 编译器:g++ 9.4+(需支持C++17)
- 依赖库:
vsomeip(版本≥3.1.20),安装命令:sudo apt install libvsomeip-dev - DoIP作为底层传输由vsomeip的
local配置自动处理,本案例不涉及DoIP协议细节
服务接口定义
使用SOME/IP的事件组(Eventgroup)与方法(Method)机制:
- 服务ID:
0x1234 - 实例ID:
0x5678 - 方法ID:
0x0421(加法计算) - 请求载荷:8字节(两个int32,小端序)
- 响应载荷:4字节(int32结果)
完整实现代码
// calculator_service.cpp
#include <vsomeip/vsomeip.hpp>
#include <iostream>
#include <thread>
#include <cstring>
class CalculatorService {
public:
CalculatorService() : app_(vsomeip::runtime::get()->create_application("calc_service")) {}
bool init() {
if (!app_->init()) {
std::cerr << "Failed to init vsomeip" << std::endl;
return false;
}
app_->register_message_handler(
vsomeip::service_id_t(0x1234), vsomeip::instance_id_t(0x5678),
vsomeip::method_id_t(0x0421),
[this](const std::shared_ptr<vsomeip::message>& req) { on_request(req); });
app_->register_availability_handler(
vsomeip::service_id_t(0x1234), vsomeip::instance_id_t(0x5678),
[this](vsomeip::service_t s, vsomeip::instance_t i, bool avail) {
if (avail) std::cout << "Service available" << std::endl;
});
return true;
}
void start() {
app_->offer_service(vsomeip::service_id_t(0x1234), vsomeip::instance_id_t(0x5678));
app_->start();
}
private:
void on_request(const std::shared_ptr<vsomeip::message>& req) {
// 解析请求载荷:两个int32
const auto& payload = req->get_payload();
if (payload->get_length() < 8) {
std::cerr << "Invalid payload length" << std::endl;
return;
}
const uint8_t* data = payload->get_data();
int32_t a, b;
std::memcpy(&a, data, 4);
std::memcpy(&b, data + 4, 4);
int32_t result = a + b;
// 构造响应
auto resp = vsomeip::runtime::get()->create_response(req);
auto resp_payload = vsomeip::runtime::get()->create_payload();
resp_payload->set_data(reinterpret_cast<uint8_t*>(&result), 4);
resp->set_payload(resp_payload);
app_->send(resp);
std::cout << "Calc: " << a << " + " << b << " = " << result << std::endl;
}
std::shared_ptr<vsomeip::application> app_;
};
int main() {
CalculatorService svc;
if (!svc.init()) return -1;
svc.start();
// vsomeip::application::start() 会阻塞,此处不会返回
return 0;
}
编译与运行
# 编译
g++ -std=c++17 -o calc_service calculator_service.cpp -lvsomeip
# 运行(需先启动vsomeip守护进程)
vsomeipd &
./calc_service
验证方法
使用vsomeip自带的someip_test_client工具或编写简单客户端发送测试请求:
# 使用vsomeip示例客户端(需单独编译)
# 发送请求:a=5, b=3(小端序:05 00 00 00 03 00 00 00)
# 预期响应:08 00 00 00(即8)
通过条件:
- 服务端启动后控制台输出
Service available,表明服务已注册到vsomeip路由; - 客户端发送合法请求后,服务端控制台打印
Calc: 5 + 3 = 8; - 客户端收到响应载荷为
0x08 0x00 0x00 0x00(小端序int32值8)。
关键说明
- 本案例使用vsomeip的本地IPC作为传输层,DoIP网关配置由vsomeip的
vsomeipd守护进程统一管理,服务端代码无需感知DoIP细节; - 若需跨设备通信,需在vsomeip配置文件中指定DoIP端点(本案例不展开);
- 服务端启动后阻塞在
app_->start(),如需优雅退出可注册信号处理。