vsomeip 协议栈总结

什么是 SOME/IP

Scalable service-Oriented middlewarE over IP,基于 IP 的可扩展的面向服务的中间件。
SOME/IP于2011年由BMW设计,2014年纳入AUTOSAR规范。该中间件是为典型的汽车用例而设计的。
帧结构
IP 网络上的两个设备,可以通过 SOME/IP 消息通信进行通信,传输层可基于 TCP 或 UDP。下图描述了通信过程:

在这里插入图片描述

假设设备 B 上运行一个服务,该服务提供一个函数,设备 A 通过 SOME/IP 消息调用该函数,函数的执行结果再通过 SOME/IP 消息返回给设备 A。
SOME/IP 消息由两部分组成:头部和负载。
头部字段的含义:
• Service ID: 服务唯一标识。
• Method ID: 函数的标识。
• Length: 负载长度(以字节为单位),包含头部 Length 之后的 8 字节。
• Client ID: 客户端唯一标识。
• Session ID: 会话计数值,每次通信完加一。
• Protocol Version: 0x01
• Interface Version: 服务接口主版本号
• Message Type:
○ – REQUEST (0x00) 请求消息,需要服务恢复
○ – REQUEST_NO_RETURN (0x01) 请求消息,不需要服务回复
○ – NOTIFICATION (0x02) 通知消息
○ – RESPONSE (0x80) 回复消息
• Return Code:
○ – E_OK (0x00) 没有错误
○ – E_NOT_OK (0x01) 未知错误
○ – E_WRONG_INTERFACE_VERSION (0x08) 接口版本不匹配
○ – E_MALFORMED_MESSAGE (0x09) 消息反序列化错误
○ – E_WRONG_MESSAGE_TYPE (0x0A) 消息类型错误
负载:
协议需要提供序列化和反序列化的能力。
服务可以多次实例化,每一个实例通过不同的 ID 进行标识,实例 ID 并不包含在 SOME/IP 消息头部字段中,需要通过不同的端口号区分不同的实例。

协议规范

通信模式

SOME/IP 支持两种通信模式: publish/subscribe 和 request/response。
在这里插入图片描述
request/response :是对远程过程调用标准机制的实现,客户端可以通过 request 消息调用服务端的函数,结果通过 response 消息返回。
publish/subscribe :客户端可以通过 subscribe 向服务端订阅事件,当事件发生时,服务端可以主动通知客户端事件的状态。

服务发现

SOME/IP 协议是通过 SOME/IP-SD 消息实现服务发现功能的。
在这里插入图片描述
局域网中的每个设备会定期广播(组播)包含由该设备提供的所有服务的 “offer” 消息。该消息消息通过UDP发送。客户端通过通过解析该消息可以获取服务实例的位置(ip和port)。如果客户端应用程序需要服务,但目前没有服务提供,那么也可以发送 “find” 消息。
SOME/IP-SD 协议还可以检测服务实例是否正在运行,以及实现 publish/subscribe 处理。

Vsomeip 实现

Vsomeip 使用

服务端程序:

#include <iomanip>
#include <iostream>
#include <sstream>
#include <vsomeip/vsomeip.hpp>

#define SAMPLE_SERVICE_ID 0x1236
#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::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();
}

客户端程序:

#include <condition_variable>
#include <iomanip>
#include <iostream>
#include <sstream>
#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;

bool running_ = true;
bool blocked_ = false;
bool is_available_ = false;

void run() {
    std::shared_ptr<vsomeip::message> request;
    request = vsomeip::runtime::get()->create_request(true);
    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(('a' + i) % 256);
    }
    its_payload->set_data(its_payload_data);
    request->set_payload(its_payload);

    while (running_) {
        {
            std::unique_lock<std::mutex> its_lock(mutex);
            while (!blocked_) condition.wait(its_lock);
            if (is_available_) {
                app->send(request);
                std::cout << "Client/Session [" << std::setw(4)
                          << std::setfill('0') << std::hex
                          << request->get_client() << "/" << std::setw(4)
                          << std::setfill('0') << std::hex
                          << request->get_session()
                          << "] sent a request to Service [" << std::setw(4)
                          << std::setfill('0') << std::hex
                          << request->get_service() << "." << std::setw(4)
                          << std::setfill('0') << std::hex
                          << request->get_instance() << "]" << std::endl;
                blocked_ = false;
            }
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
}

void on_message(const std::shared_ptr<vsomeip::message> &_response) {
    std::shared_ptr<vsomeip::payload> its_payload = _response->get_payload();
    vsomeip::length_t l = its_payload->get_length();

    // Get payload
    std::stringstream ss;
    f
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翻滚吧香香

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值