什么是 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

2070

被折叠的 条评论
为什么被折叠?



