3. SOME/IP服务接口定义与代码生成

SOME/IP服务接口定义与代码生成 学习卡片

任务目标

在SOME/IP开发中,服务接口定义是通信的契约。本案例将完成一个最小可复现的接口定义与代码生成闭环:使用vsomeip提供的接口描述方式,定义一个包含方法调用(Method)和事件通知(Event)的简单服务,并生成对应的服务端与客户端桩代码骨架,验证接口定义与代码生成流程的正确性。

环境与依赖

  • 操作系统:Linux(Ubuntu 20.04+)
  • 依赖库:libvsomeip-dev(版本≥3.1)
  • 代码生成工具:vsomeip的代码生成器需要Python 3.6+,并安装vsomeip-gen(通常随vsomeip源码包提供)

接口定义(.json文件)

vsomeip使用JSON格式描述服务接口。以下定义了一个服务(Service ID: 0x1234),包含一个方法add(Method ID: 0x0001)和一个事件status(Event ID: 0x8001,Eventgroup: 0x01):

{
    "name": "CalculatorService",
    "service_id": "0x1234",
    "version": "1.0",
    "methods": [
        {
            "name": "add",
            "method_id": "0x0001",
            "in_params": [
                {"name": "a", "type": "int32"},
                {"name": "b", "type": "int32"}
            ],
            "out_params": [
                {"name": "result", "type": "int32"}
            ]
        }
    ],
    "events": [
        {
            "name": "status",
            "event_id": "0x8001",
            "eventgroup_id": "0x01",
            "params": [
                {"name": "value", "type": "boolean"}
            ]
        }
    ]
}

代码生成

使用vsomeip-gen工具生成C++桩代码。将上述JSON保存为calculator.json,执行:

vsomeip-gen calculator.json --output-dir ./generated

生成的文件包括:calculator_service.hpp(服务端接口)、calculator_service.cpp(服务端实现骨架)、calculator_client.hpp(客户端代理)、calculator_client.cpp(客户端实现骨架)。

服务端实现(关键代码)

在生成的服务端骨架中,实现add方法逻辑并周期发送status事件。以下为最小可运行的服务端实现:

#include <vsomeip/vsomeip.hpp>
#include "generated/calculator_service.hpp"

class CalculatorServiceImpl : public CalculatorService {
public:
    void add(const std::shared_ptr<vsomeip::message>& request,
             const std::shared_ptr<vsomeip::message>& response) override {
        // 解析请求参数
        auto payload = request->get_payload();
        int32_t a = payload->get_data()[0] | (payload->get_data()[1] << 8);
        int32_t b = payload->get_data()[2] | (payload->get_data()[3] << 8);
        int32_t result = a + b;

        // 构造响应
        std::vector<vsomeip::byte_t> data(4);
        data[0] = result & 0xFF;
        data[1] = (result >> 8) & 0xFF;
        data[2] = (result >> 16) & 0xFF;
        data[3] = (result >> 24) & 0xFF;
        response->set_payload(std::make_shared<vsomeip::payload>(data));
    }

    void start() {
        // 注册服务并启动
        register_service();
        std::thread([this]() {
            while (true) {
                std::this_thread::sleep_for(std::chrono::seconds(2));
                notify_status(true);  // 发送事件
            }
        }).detach();
        vsomeip::runtime::get()->start();
    }
};

int main() {
    auto service = std::make_shared<CalculatorServiceImpl>();
    service->start();
    return 0;
}

客户端调用(关键代码)

#include <vsomeip/vsomeip.hpp>
#include "generated/calculator_client.hpp"

class CalculatorClientImpl : public CalculatorClient {
public:
    void on_status(bool value) override {
        std::cout << "收到事件: status=" << value << std::endl;
    }

    void call_add() {
        int32_t result = add(3, 5);
        std::cout << "add(3,5) = " << result << std::endl;
    }
};

int main() {
    auto client = std::make_shared<CalculatorClientImpl>();
    client->init();
    client->call_add();
    std::this_thread::sleep_for(std::chrono::seconds(5));  // 等待事件
    return 0;
}

编译与运行

# 编译服务端
g++ -std=c++11 -o server server.cpp generated/calculator_service.cpp -lvsomeip -lpthread
# 编译客户端
g++ -std=c++11 -o client client.cpp generated/calculator_client.cpp -lvsomeip -lpthread

# 终端1:启动服务端
./server
# 终端2:启动客户端
./client

验证方法

  1. 编译通过:上述编译命令无错误,生成可执行文件。
  2. 服务注册成功:服务端启动后,终端输出类似Service 0x1234 registered的日志。
  3. 方法调用成功:客户端输出add(3,5) = 8,说明请求-响应链路正常。
  4. 事件接收成功:客户端在5秒内输出收到事件: status=1(每2秒一次),说明事件通知链路正常。

若以上输出均符合预期,则接口定义与代码生成流程验证通过。