SOME/IP编程
配置环境变量
vsomeip应用启动时以下的环境变量会被读取:
VSOMEIP_APPLICATION_NAME,赋予当前程序在vsomeip中使用的名字。vsomeip会通过改名字在配置文件中进行匹配查找。该名字与二进制可执行文件的名字是不一样的。
VSOMEIP_CONFIGURATION,vsomeip默认会使用配置文件/etc/vsomeip.json或者包含配置文件的文件夹/etc/vsomeip。你可以通过该变量使vsomeip使用自定义的配置文件。
VSOMEIP_MANDATORY_CONFIGURATION_FILES,vsomeip允许使用mandatory配置文件来加快应用的启动速度(此时,除负责连接某些外部设别的程序之外,其他所有程序运行时都需要按照mandatory配置文件工作)。默认mandatory配置文件是:vsomeip_std.json,vsomeip_app.json和vsomeip_plc.json。
基础知识:
析构函数:
-
对象离开其作用域:当一个局部对象的作用域结束时(例如在函数执行结束或代码块结束时),其析构函数会被自动调用。
-
动态分配对象的释放:通过new关键字动态分配的对象,必须使用delete来释放。在调用delete释放动态分配的对象时,其析构函数会被自动调用。
-
对象作为成员变量的析构:当一个对象是另一个类的成员变量时,当该类的析构函数被调用时,它的成员变量的析构函数会被自动调用。
-
继承和多态:在继承体系中,如果基类的析构函数是虚函数,当使用基类指针指向派生类对象并通过该指针删除对象时,会自动调用派生类的析构函数。
(void)argc;
(void)argv;
这样做只是为了满足编译器的要求,告诉编译器你有意不使用这些参数,从而消除编译器警告。
虚函数
override
class Base {
public:
virtual void foo() {
std::cout << "Base::foo() called." << std::endl;
}
};
class Derived : public Base {
public:
// 使用 override 表示重写基类虚函数 foo
void foo() override {
std::cout << "Derived::foo() called." << std::endl;
}
};
在上述示例中,Derived类中的foo()函数使用override关键字,它表示该函数是对基类Base中的虚函数foo()进行重写。如果Base类中没有名为foo()的虚函数,或者它不是虚函数,编译器将产生错误。
virtual void start() = 0
上述是C++中声明一个纯虚函数的语法。它是一个虚函数,没有实际的实现。任何派生类必须提供自己的start()函数实现,否则派生类也会成为抽象类。通常,希望定义一个接口(或者称为基类)并要求派生类提供特定行为时会使用纯虚函数。
如何改硬件的mac地址?
- 停用卡
sudo ip link set dev xxxx(网卡名) down - 分配mac地址
sudo ip link set dev xxxx address XX:XX:XX:XX:XX:XX - 激活卡
sudo ip link set dev xxxx up - 检查是否已更改
ip link ls
API
application的创建
using namespace vsomeip;
std::shared_ptr<runtime> rtm_ = runtime::get();
std::shared_ptr<application> app_= rtm_->create_application("name")
源码如下:
std::shared_ptr<application> runtime_impl::create_application(
const std::string &_name, const std::string &_path) {
static std::uint32_t postfix_id = 0; // 计数id
std::lock_guard<std::mutex> its_lock(applications_mutex_); // 上锁
std::string its_name = _name; // 程序名
auto found_application = applications_.find(_name); // 去map里面找程序名
if( found_application != applications_.end()) {
its_name += "_" + std::to_string(postfix_id++); // 如果找到了就做重名处理
}
std::shared_ptr<application> application
= std::make_shared<application_impl>(its_name, _path); // 创建一个application类型的智能指针
applications_[its_name] = application; // 放到map里面
return application; // 返回application的智能指针
}
初始化的变量:
application_impl::application_impl(const std::string &_name)
: runtime_(runtime::get()),
client_(VSOMEIP_CLIENT_UNSET), //默认client id = 0xFFFF
session_(0), //初始化session id = 0
is_initialized_(false),
name_(_name), //应用名称
work_(std::make_shared<boost::asio::io_service::work>(io_)),
//route_manager指针, 有两种角色,一个是host,一个是proxy,实现不一样
routing_(0),
//初始化app状态为DEREGISTERRED状态
state_(state_type_e::ST_DEREGISTERED),
//安全模式
security_mode_(security_mode_e::SM_OFF),
#ifdef VSOMEIP_ENABLE_SIGNAL_HANDLING
signals_(io_, SIGINT, SIGTERM),
catched_signal_(false),
#endif
is_dispatching_(false),
max_dispatchers_(VSOMEIP_MAX_DISPATCHERS),
max_dispatch_time_(VSOMEIP_MAX_DISPATCH_TIME),
stopped_(false),
block_stopping_(false),
is_routing_manager_host_(false),
stopped_called_(false),
watchdog_timer_(io_),
client_side_logging_(false)
noexcept是C++11引入的关键字,用于指示函数不会抛出异常。它放置在函数声明或定义的尾部,并用于表示函数在运行时不会引发任何异常。
void myFunction() noexcept;
需要注意的是,如果在noexcept声明的函数内部抛出了异常,程序将会调用std::terminate函数,导致程序终止。因此,使用noexcept时需要确保函数内部不会引发异常,否则会破坏程序的正常执行。
init():
配置模块
-
获取名字
-
application_impl.cpp 142行
configuration_ = its_configuration_plugin->get_configuration(name_, path_);
关键是这个get_configuration(name_, path_)
函数
std::shared_ptr<configuration>
configuration_plugin_impl::get_configuration(const std::string &_name,
const std::string &_path) {
std::lock_guard<std::mutex> its_lock(mutex_);
if (!default_) {
default_ = std::make_shared<cfg::configuration_impl>(_path);
default_->load(_name);
}
return default_;
default_->load(_name)
函数主体:
bool configuration_impl::load(const std::string &_name)
内部逻辑:
- 配置默认环境
- 如果有本地环境配置,覆盖配置
- 如果有存在的环境配置,覆盖配置
路由配置加载:
bool
configuration_impl::load_routing(const configuration_element &_element)
路由配置
创建路由
if (is_routing_manager_host_) {
// 创建host类型的路由
VSOMEIP_INFO << "Instantiating routing manager [Host].";
if (client_ == VSOMEIP_CLIENT_UNSET) {
client_ = static_cast<client_t>(
(configuration_->get_diagnosis_address() << 8)
& configuration_->get_diagnosis_mask());
utility::request_client_id(configuration_, name_, client_);
}
routing_ = std::make_shared<routing_manager_impl>(this);
} else {
// 创建proxy类型的路由
VSOMEIP_INFO << "Instantiating routing manager [Proxy].";
routing_ = std::make_shared<routing_manager_client>(this, client_side_logging_, client_side_logging_filter_);
}
创建host或proxy类型的路由
routing_manager_impl::routing_manager_impl(routing_manager_host *_host) :
routing_manager_base(_host),
version_log_timer_(_host->get_io()),
if_state_running_(false),
sd_route_set_(false),
routing_running_(false),
status_log_timer_(_host->get_io()),
memory_log_timer_(_host->get_io()),
ep_mgr_impl_(std::make_shared<endpoint_manager_impl>(this, io_, configuration_)),
pending_remote_offer_id_(0),
last_resume_(std::chrono::steady_clock::now().min()),
statistics_log_timer_(_host->get_io()),
ignored_statistics_counter_(0)
{
}
路由模块初始化
routing_->init()
将通信端点管理器赋给父类中的ep_mgr_指针
routing_manager_base::init(ep_mgr_impl_)
创建stub端,即创建一个用于本地域通讯的服务端
bool is_successful = host_->get_endpoint_manager()->create_routing_root(
root_, is_socket_activated_, shared_from_this());
路由模块初始化时序图:
组播地址配置:
route add -nv 224.224.224.245 dev eth0和route add -net 224.0.0.0/4 dev eth0的区别
- route add -nv 224.224.224.245 dev eth0:
这个命令的目的是将特定的目标IP地址(224.224.224.245)配置到指定的网络接口(eth0)上。
-n 参数告诉系统不要进行反向DNS查找,以IP地址形式显示输出。
-v 参数用于显示详细的操作信息,通常是"verbose"的缩写。 - route add -net 224.0.0.0/4 dev eth0:
这个命令的目的是将属于特定目标IP地址范围(224.0.0.0/4)的所有流量配置到指定的网络接口(eth0)上。
-net 参数表示将目标地址视为一个网络地址范围,而不是单独的IP地址。
224.0.0.0/4 是一个组播(multicast)IP地址范围,用于多点通信。
总的来说,第一个命令是将特定IP地址配置到网络接口上,而第二个命令是将一个IP地址范围(用于组播)配置到网络接口上。在某些情况下,你可能需要根据具体需求来选择使用哪种命令。