SOME/IP
原文出自:https://github.com/GENIVI/vsomeip/wiki/vsomeip-in-10-minutes
GitHub仓库的wiki 页,这篇wiki写得非常好,读完对someIP应该能有一个比较深刻的认识。
1 SOME/IP简介
SOME/IP是“可扩展的面向服务的基于IP的中间件”的缩写。此中间件是为典型的汽车用例设计的,并且与AUTOSAR兼容(至少在线格式级别上)。
在本wiki中,我们不想进一步深入讨论另一种中间件规范的原理,但希望对SOME/IP规范及其开放源码实现vsomeip的基本结构给出一个粗略的概述,而不阐释其完整性。
让我们从some/IP规范的三个主要部分开始:
1. 线框格式
2. 协议
3. 服务发现
原则上,SOME/IP通信由通过IP在设备或订阅者之间发送的消息组成。参考以下图片:
这里有两个装置(A和B);设备A向设备B发送一个SOME/IP消息,并返回一条消息。底层传输协议可以是TCP或UDP;对于消息本身来说,这没有什么区别。现在我们假设在设备B上运行一个服务,该服务提供了一个函数,这个函数通过这个消息从设备A调用,返回的消息就是结果。
SOME/IP消息有两部分:消息头和有效负载。图中所示的消息头主要由标识符组成:
· Service ID: unique identifier for each service 每个服务唯一的标识
· Method ID: 0-32767 for methods,32768-65535 for events
· Length: length of payload in byte (covers also the next IDs, that means 8 additional bytes)
· Client ID: unique identifier for the calling client inside the ECU; has to be unique in the overall vehicle ECU里的发出请求的客户端的唯一标识,在整车中都必须是唯一的
· Session ID: identifier for session handling; has to be incremented for each call 会话ID,自动增加
· Protocol Version: 0x01
· Interface Version: major version of the service interface
· Message Type: – REQUEST (0x00)A request expecting a response (even void) – REQUEST_NO_RETURN (0x01) Afire&forget request – NOTIFICATION (0x02) A request of a notification/event callback expecting no response – RESPONSE (0x80) The response message 消息类型 期望回复的请求、只请求不回复、通知/事件(不回复)
· Return Code: – E_OK (0x00) No error occurred – E_NOT_OK (0x01) An unspecified error occurred –
E_WRONG_INTERFACE_VERSION (0x08) Interface version mismatch --E_MALFORMED_MESSAGE (0x09) Deserialization error, so that payload cannot be deserialized – E_WRONG_MESSAGE_TYPE (0x0A) An unexpected message type was received (e.g. RE-QUEST_NO_RETURN for a method defined as RE-QUEST) 返回码
我们看到,对于正常的函数调用有“请求”和“响应”,对于客户端已经订阅的事件有通知消息。错误被报告为正常响应或通知,但带有适当的返回码。
有效负载包含序列化的数据。该图显示了在传输数据结构时仅具有基本数据类型的嵌套结构的简单情况下的序列化。在这种情况下,这很简单:结构元素只是扁平化,这意味着它们只是一个接一个地写入到有效负载中。
2 SOME/IP协议
在本节中,主要有两点很重要:
1. 所谓的传输绑定(UDP和TCP)
2. 基本的通信模式 发布/订阅和请求/响应。
如上所述,底层传输协议可以是UDP或TCP。在UDP情况下,SOME/IP消息不是片段;可以是一个UDP包中有多个消息,但是一个消息不能超过UDP包的长度(最多1400字节)。较大的消息必须通过TCP传输。在这种情况下,使用了TCP的鲁棒特性。如果TCP流中出现同步错误,SOME/IP规范允许所谓的魔术cookie,以便再次查找下一条消息的开头。
请注意,必须实例化服务接口,而且由于同一个接口可能有多个实例,因此定义的实例必须有一个附加标识符(实例ID)。然而,实例ID不是SOME/IP消息头的一部分。实例通过传输协议的端口号来标识;这意味着不可能在同一端口上提供同一接口的多个实例。
请看看下面的图片,它显示了基本的SOME/IP通信模式:
除了用于远程过程调用的标准请求/响应机制外,还有用于事件的发布/订阅模式。请注意,SOME/IP协议中的事件总是分组在一个事件组中;因此,只能订阅事件组,而不能订阅事件本身。SOME/IP规范也知道“字段”;在这种情况下,setter/getter方法遵循请求/响应模式,通知也是基于发生改变的事件(其实归根结底,someip就只有两种机制,分别是请求响应,订阅通知,只是对于主动和被动,响应和不响应又作了区分而已,所以有时候分不清到底有多少种接口)。订阅本身是通过SOME/IP服务发现完成的。
3 SOME/IP服务发现
SOME/IP服务发现用于定位服务实例,检测服务实例是否在运行,以及实现发布/订阅处理。这主要是通过所谓的offer信息来实现的;这意味着每个设备广播(多播)消息,其中包含所有服务,这是由该设备提供。SOME/IP SD消息是通过UDP发送的。如果客户端应用程序需要服务,但目前没有提供,那么也可以发送“查找消息”。其他SOME/IP SD消息可以用于发布或订阅一个事件组(enentgroup)。
下面的图片显示了SOME/IP SD消息的一般结构。
一开始这就足够了。更多细节将在后面的示例中讨论,或者可以在规范中阅读。
4 vsomeip简短概述
在开始实现这个介绍性示例之前,让我们先简单了解一下SOME/IP的GENIVI实现(称为vsomeip)的基本结构。
如图所示,vsomeip不仅包括设备间的SOME/IP通信(外部通信),还包括内部进程间通信。两个设备通过所谓的通信端点进行通信,这些端点确定使用的传输协议(TCP或UDP)及其参数作为端口号或其他参数。所有这些参数都是可以在vsomeip配置文件(json文件,请参阅vsomeip用户指南)中设置的配置参数。
内部通信是通过本地端点完成的,这些本地端点由unix域套接字使用Boost.Asio库实现。由于这种内部通信不通过中心组件(例如D-Bus守护进程)进行路由,因此速度非常快。
中央vsomeip路由管理器只有在消息必须发送到外部设备时才能获取消息,并且分发来自外部的消息。每个设备只有一个路由管理器;如果没有配置任何内容,第一个运行的vsomeip应用程序也会启动路由管理器。
vsomeip没有实现数据结构的序列化!这由CommonAPI的SOME/IP绑定涵盖。vsomeip仅仅涵盖了一些/IP协议和服务发现。
这是关于SOME/IP和vsomeip的一个非常简短的概述。但对于第一次开始,这已经足够了;更多的细节将在示例中直接解释。
5 准备/先决条件
如前所述,vsomeip需要Boost.Asio库,因此请确保在您的系统上安装了BOOST(至少1.55版本)。当Boost成功安装后,您可以轻松构建vsomeip:
sudo apt-get install libboost-all-dev
$ cd vsomeip
<.>/vsomeip$mkdir build
<.>/vsomeip$cd build
<.>/vsomeip/build$cmake ..
<.>/vsomeip/build$make
这个工作,但为了避免一些特殊的问题之后,我建议添加至少一个参数到你的CMake调用:
<.>/vsomeip/build$ cmake -DENABLE_SIGNAL_HANDLING=1 ..
这个参数确保您可以毫无问题地终止vsomeip应用程序(否则可能是在使用Ctrl-C停止应用程序时没有正确地删除共享内存段/dev/shm/vsomeip)。
(注:这个有必要添加,否则终止程序的时候可能出现进程关闭不彻底的情况,比较麻烦)
#include <vsomeip/vsomeip.hpp>
std::shared_ptr< vsomeip::application > app;
int main() {
app = vsomeip::runtime::get()->create_application("World");
app->init();
app->start();
}
这非常简单:您必须首先创建一个应用程序对象,然后初始化并启动它。init方法必须首先调用,之后创建vsomeip应用程序并执行以下步骤来初始化:
- 加载配置
- 决定路由配置和初始化路由
- 安装信号处理
为了启动消息处理,必须在init之后调用start方法。接收到的消息通过套接字处理,并使用注册的回调将它们传递给用户应用程序。
ready :+1 (下一个准备工作)
创建下面所示的cmake文件用于构建应用程序
cmake_minimum_required (VERSION 2.8)
set (CMAKE_CXX_FLAGS "-g -std=c++0x")
find_package (vsomeip 2.6.0 REQUIRED)
find_package( Boost 1.55 COMPONENTS system thread log REQUIRED )
include_directories (
${Boost_INCLUDE_DIR}
${VSOMEIP_INCLUDE_DIRS}
)
add_executable(service-example ../src/service-example.cpp)
target_link_libraries(service-example vsomeip ${Boost_LIBRARIES})
继续创建构建路径,运行cmake,构建,然后启动应用程序,你可以在控制台可以看到类似下列的输出
2017-03-20 10:38:20.885390 [info] Parsed vsomeip configuration in 0ms
2017-03-20 10:38:20.889637 [info] Default configuration module loaded.
2017-03-20 10:38:20.889797 [info] Initializing vsomeip application "World".
2017-03-20 10:38:20.890120 [info] SOME/IP client identifier configured. Using 0001 (was: 0000)
2017-03-20 10:38:20.890259 [info] No routing manager configured. Using auto-configuration.
2017-03-20 10:38:20.890367 [info] Instantiating routing manager [Host].
2017-03-20 10:38:20.890641 [info] init_routing_endpoint Routing endpoint at /tmp/vsomeip-0
2017-03-20 10:38:20.890894 [info] Client [1] is connecting to [0] at /tmp/vsomeip-0
2017-03-20 10:38:20.891039 [info] Service Discovery enabled. Trying to load module.
2017-03-20 10:38:20.891647 [info] Service Discovery module loaded.
2017-03-20 10:38:20.892045 [info] Application(World, 1001) is initialized (11, 100).
2017-03-20 10:38:20.892210 [info] Starting vsomeip application "World" using 2 threads
2017-03-20 10:38:20.892668 [info] Watchdog is disabled!
2017-03-20 10:38:20.893312 [info] Network interface "lo" is up and running.
2017-03-20 10:38:20.898471 [info] vSomeIP 2.6.2
2017-03-20 10:38:20.898708 [info] Sent READY to systemd watchdog
2017-03-20 10:38:20.898854 [info] SOME/IP routing ready.
注意:
这一步无关服务端与客户端,他只是someip的应用程序
到此你都不需要任何配置文件
让我们详细讨论一些要点。
首先,您会看到已加载的配置;您没有配置,因此使用默认配置。
您没有为您的应用程序配置客户端ID;因此,由于vsomeip特性,即自动配置,会找到一个合适的客户端ID。第一个数字是0x0001。
路由管理器也没有配置;因此,路由管理器将从系统中的第一个vsomeip应用程序自动启动,这是服务示例。
默认情况下是启用服务发现,没有静态路由。这需要一些配置参数。
最后一个init()输出是Application(World, 1)被初始化(11,100)。
最后的两个数字意味着如果一个回调阻塞超过100ms, vsomeip使用的最大调度程序数是11。可以配置这些参数。
默认情况下,创建两个线程来接收some/IP消息;这允许vsomeip并行地处理长消息。
然后您会看到当前的vsomeip版本,some/IP路由已经准备好了。
到目前为止,应用程序没有做太多的工作,而且客户机和服务之间没有区别。现在,让我们假设我们的服务示例是一个服务,并且我们希望编写一个希望使用该服务的客户机。在第一步中,我们必须触发应用程序来提供服务的实例。这可以通过在第一个示例中添加一个offer_service命令来完成:
#include <vsomeip/vsomeip.hpp>
#define SAMPLE_SERVICE_ID 0x1234
#define SAMPLE_INSTANCE_ID 0x5678
std::shared_ptr< vsomeip::application > app;
int main() {
app = vsomeip::runtime::get()->create_application("World");
app->init();
app->offer_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
app->start();
}
下一步我们写一个程序检查是否"world"程序是可获得的(可用的),下面的代码创建一个名为"hello"的应用程序
#include <iomanip>
#include <iostream>
#include <vsomeip/vsomeip.hpp>
#define SAMPLE_SERVICE_ID 0x1234
#define SAMPLE_INSTANCE_ID 0x5678
std::shared_ptr< vsomeip::application > app;
void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) {
std::cout << "Service ["
<< std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance
<< "] is " << (_is_available ? "available." : "NOT available.") << std::endl;
}
int main() {
app = vsomeip::runtime::get()->create_application("Hello");
app->init();
app->register_availability_handler(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, on_availability);
app->request_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
app->start();
}
为了尽可能的简单,我省略了所有能省略的检查,比如是否注册成功,作为客户端你想要使用服务的时候,你需要注册回调函数,客户端的输出应该像这样:
Service [1234.5678] is NOT available.
2017-03-21 04:14:37.720313 [info] REQUEST(0002): [1234.5678:255.4294967295]
Service [1234.5678] is available.
当someip事件循环启动的时候会调用回调函数
服务端会多这样一行:
2017-03-21 04:14:33.850964 [info] OFFER(0001): [1234.5678:0.0]
请求/响应
从最简单的someip应用的开始,我们创建了一个服务用来提供服务接口的示例,也创建了一个客户端想要使用这个接口。接下来是时候在服务端实现真正能被客户端调用的函数了。
服务端必须准备接受消息;可以通过注册一个message hander :
#include <iomanip>
#include <iostream>
#include <sstream>
#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;
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, true);
}
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 <iomanip>
#include <iostream>
#include <sstream>
#include <condition_variable>
#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;
void run() {
std::unique_lock<std::mutex> its_lock(mutex);
condition.wait(its_lock);
std::shared_ptr< vsomeip::message > request;
request = vsomeip::runtime::get()->create_request();
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(i % 256);
}
its_payload->set_data(its_payload_data);
request->set_payload(its_payload);
app->send(request, true);
}
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;
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 << "CLIENT: Received message with Client/Session ["
<< std::setw(4) << std::setfill('0') << std::hex << _response->get_client() << "/"
<< std::setw(4) << std::setfill('0') << std::hex << _response->get_session() << "] "
<< ss.str() << std::endl;
}
void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _is_available) {
std::cout << "CLIENT: Service ["
<< std::setw(4) << std::setfill('0') << std::hex << _service << "." << _instance
<< "] is "
<< (_is_available ? "available." : "NOT available.")
<< std::endl;
condition.notify_one();
}
int main() {
app = vsomeip::runtime::get()->create_application("Hello");
app->init();
app->register_availability_handler(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, on_availability);
app->request_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
app->register_message_handler(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_METHOD_ID, on_message);
std::thread sender(run);
app->start();
}
像在服务端一样,我们需要注册一个消息处理程序来接收调用的响应。原则上,创建发送消息(请求)是非常容易的。只需通过调用create_request()获得请求对象,设置服ID、实例ID和方法ID,并在最后使用序列化的数据编写有效负载。在这个例子中,我们在有效负载中写入从0到9的值(std::vector<vsomeip: byte_t>)。
当我们尝试从客户端向服务发送请求时,会遇到一个小问题。在我们发送消息之前,必须启动应用程序(app->start()),因为我们需要一个运行的事件循环来处理消息。但是方法app->start()没有返回,因为它内部有正在运行的事件循环。因此,我们启动一个线程(运行),并在此线程中等待可用性回调的返回,然后调用app->send(request, true)。
输出
2017-03-21 08:08:08.033710 [info] REQUEST(1002): [1234.5678:255.4294967295]
CLIENT: Service [1234.5678] is available.
2017-03-21 08:08:08.034182 [info] Client [1002] is connecting to [1001] at /tmp/vsomeip-1001
SERVICE: Received message with Client/Session [1002/0001] 00 01 02 03 04 05 06 07 08 09
CLIENT: Received message with Client/Session [1002/0001] 09 08 07 06 05 04 03 02 01 00
订阅/通知
到目前为止,我们已经创建了实现方法的服务和调用该方法的客户机。但这并不是唯一的可能 ,SOME/IP规范还描述了事件处理。这意味着如果订阅者感兴趣,应用程序可以向其发送事件。通过定义setter和getter方法,可以实现提供属性的服务。
为了使它不太复杂,我们在示例中删除了方法调用的实现,并实现了事件处理。首先让我们看一下服务。
请在您的main 函数添加以下几行:
const vsomeip::byte_t its_data[] = { 0x10 };
payload = vsomeip::runtime::get()->create_payload();
payload->set_data(its_data, sizeof(its_data));
std::set<vsomeip::eventgroup_t> its_groups;
its_groups.insert(SAMPLE_EVENTGROUP_ID);
app->offer_event(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENT_ID, its_groups, true);
app->notify(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENT_ID, payload);
请注意
- 你必须提供的事件,以宣布这个事件的存在,以世界的其他地方。
- 通过notify方法,您可以将事件发送给任何订阅了该事件的人。
- 每个事件都属于一个事件组!但是它也可以属于几个事件组。
- 事件并不独立于服务而存在;如果未提供该服务,则该服务对客户端不可用,且客户端无法订阅。
在客户端实现以下(为了更好的理解,我省略了之前讨论的一切):
...
void run() {
std::unique_lock<std::mutex> its_lock(mutex);
condition.wait(its_lock);
std::set<vsomeip::eventgroup_t> its_groups;
its_groups.insert(SAMPLE_EVENTGROUP_ID);
app->request_event(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENT_ID, its_groups, true);
app->subscribe(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, SAMPLE_EVENTGROUP_ID);
}
void on_message(const std::shared_ptr<vsomeip::message> &_response) {
std::stringstream its_message;
its_message << "CLIENT: received a notification for event ["
<< std::setw(4) << std::setfill('0') << std::hex
<< _response->get_service() << "."
<< std::setw(4) << std::setfill('0') << std::hex
<< _response->get_instance() << "."
<< std::setw(4) << std::setfill('0') << std::hex
<< _response->get_method() << "] to Client/Session ["
<< std::setw(4) << std::setfill('0') << std::hex
<< _response->get_client() << "/"
<< std::setw(4) << std::setfill('0') << std::hex
<< _response->get_session()
<< "] = ";
std::shared_ptr<vsomeip::payload> its_payload = _response->get_payload();
its_message << "(" << std::dec << its_payload->get_length() << ") ";
for (uint32_t i = 0; i < its_payload->get_length(); ++i)
its_message << std::hex << std::setw(2) << std::setfill('0')
<< (int) its_payload->get_data()[i] << " ";
std::cout << its_message.str() << std::endl;
}
...
int main() {
app = vsomeip::runtime::get()->create_application("Hello");
app->init();
app->register_availability_handler(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID, on_availability);
app->request_service(SAMPLE_SERVICE_ID, SAMPLE_INSTANCE_ID);
app->register_message_handler(vsomeip::ANY_SERVICE, vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD, on_message);
std::thread sender(run);
app->start();
}
您可以看到,实现没有任何困难:
- 同样,您需要eventgroup来订阅事件。
- 在您可以订阅之前,您必须请求事件。
- 接收事件只需注册一个标准消息处理程序;在这种情况下,您可以使用非常方便的通配符。
2017-04-06 03:47:46.424942 [info] REGISTER EVENT(0001): [1234.5678.8778:is_provider=true]
2017-04-06 03:47:51.851654 [info] REGISTER EVENT(0002): [1234.5678.8778:is_provider=false]
...
2017-04-06 03:47:51.856821 [info] SUBSCRIBE(0002): [1234.5678.4465:ffff:0]
2017-04-06 03:47:51.861330 [info] SUBSCRIBE ACK(0001): [1234.5678.4465.ffff]
方括号中的数字同样是客户端id;我首先启动了服务,因此服务从自动配置中得到了数字1,客户端得到了数字2。
两个设备之间的通信
SOME / IP并不是为一个设备内的进程间通信而发明的(例如,作为D-Bus),而是为多个设备之间的基于IP的通信而发明的。如果要使用到目前为止为两个设备之间的通信开发的示例,则无需更改C ++代码。但是您必须编写vsomeip配置文件。请查看vsomeip用户指南以了解详细信息;在这里,我们仅讨论使系统运行的要点。
首先,我将首先丢失一些有关vsoemip配置的介绍性文字。
- 堆栈由一个或多个json格式的文件(http://www.json.org/)配置。
- json文件的标准文件夹为/etc/vsomeip。
- 也可以通过设置环境变量来更改此文件夹或定义单个配置文件VSOMEIP_CONFIGURATION。
- 也可以将配置文件复制到包含可执行应用程序的文件夹(本地配置)。
对于以下配置示例,我假设服务在具有该地址的设备上运行,172.17.0.2而客户端具有该地址172.17.0.1。
首先,让我们看一个配置服务的示例。
{
"unicast" : "172.17.0.2",
"logging" :
{
"level" : "debug",
"console" : "true",
"file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" },
"dlt" : "false"
},
"applications" :
[
{
"name" : "World",
"id" : "0x1212"
}
],
"services" :
[
{
"service" : "0x1234",
"instance" : "0x5678",
"unreliable" : "30509"
}
],
"routing" : "World",
"service-discovery" :
{
"enable" : "true",
"multicast" : "224.224.224.245",
"port" : "30490",
"protocol" : "udp",
"initial_delay_min" : "10",
"initial_delay_max" : "100",
"repetitions_base_delay" : "200",
"repetitions_max" : "3",
"ttl" : "3",
"cyclic_offer_delay" : "2000",
"request_response_delay" : "1500"
}
}
For the communication via IP the unicast address is mandatory. Let’s discuss the other entries:
- logging: These settings are optional; set “console”=true in order to
see the log messages on the console. - applications: You can define for each application (you created it by create_application()) a fixed client ID instead of having it determined by the autoconfiguration. This will help you later to identify your application in traces. Here it is mandatory to set the client ID, because the client ID must be unique in your network. If you don’t set the clientID the autoconfiguration will calculate the clientID 1 on each device and the communication will not work.
- services: For each service instance it must be defined under which port it can be reached. If the port is “unreliable” it is an UDP port, if it is “reliable”, TCP will be the transport layer.
- routing: There is only one routing manager per device. This routing manager will be attached to the first vsomeip application which starts or to the application that is defined here.
- service-discovery: All these parameters only make sense if the service discovery is enabled. In this case the mandatory parameters are the multicast address which is used for sending the service discovery messages and port and protocol. The other parameters determine how often offer messages are sent, with whhich delay and so on. Please have a look to he user guide or teh SOME/IP specification.
确保您的设备已配置为接收多播消息(例如,
通过 route add -nv 224.224.224.245 dev eth0
或类似的;这取决于你的以太网设备的名称)。
考虑客户端的以下配置:
{
"unicast" : "172.17.0.1",
"logging" :
{
"level" : "debug",
"console" : "true",
"file" : { "enable" : "false", "path" : "/var/log/vsomeip.log" },
"dlt" : "false"
},
"applications" :
[
{
"name" : "Hello",
"id" : "0x1313"
}
],
"routing" : "Hello",
"service-discovery" :
{
"enable" : "true",
"multicast" : "224.224.224.245",
"port" : "30490",
"protocol" : "udp",
"initial_delay_min" : "10",
"initial_delay_max" : "100",
"repetitions_base_delay" : "200",
"repetitions_max" : "3",
"ttl" : "3",
"cyclic_offer_delay" : "2000",
"request_response_delay" : "1500"
}
}
由于客户端不提供服务,“服务”设置是不必要的
THE END