SOME/IP开源库Vsomeip分析2-hello_world_service分析

前言

上一篇文章中我们主要介绍了vsomeip库如何编译,以及成功的运行了helloworld的程序。

这一篇主要分析helloworld程序的服务端的运行。

相关代码目录:

examples/hello_world/hello_world_service_main.cpp

examples/hello_world/hello_world_service.hpp

Main函数

首先从main函数开始分析,这里helloworld主要调用了hello_world_service类去做初始化和启动的过程。

int main(int argc, char **argv)
{
	(void)argc;
	(void)argv;

	hello_world_service hw_srv;
#ifndef VSOMEIP_ENABLE_SIGNAL_HANDLING
	hw_srv_ptr = &hw_srv;
	signal(SIGINT, handle_signal);
	signal(SIGTERM, handle_signal);
#endif
	if (hw_srv.init()) {
		hw_srv.start();
		return 0;
	} else {
		return 1;
	}
}

关于信号相关的机制,本次暂时不做分析。我们先看非信号情况下的流程。

构造函数

// Get the vSomeIP runtime and
// create a application via the runtime, we could pass the application name
// here otherwise the name supplied via the VSOMEIP_APPLICATION_NAME
// environment variable is used
//这里的create_application(const std::string &_name)可以指定对应的name的
hello_world_service() :
	rtm_(vsomeip::runtime::get()),
	app_(rtm_->create_application()),
	stop_(false),
	stop_thread_(std::bind(&hello_world_service::stop, this))
{
}

默认构造函数中,创建对应someip的runtime对象,application对象。

这里构造函数中,create_application的时候,是可以指定对应的application name的,这里在官方的代码中,相关application name的指定是在我们启动helloworld程序的时候使用环境变量的方式指定的。

我理解这里后续工程化实现的时候,肯定是需要再代码里面指定。

初始化阶段

main函数中调用了对应的init进行初始化。这里调用到了hello_world_service这个class,并且实际服务的实现也是再这个类里面。

Init函数

bool init()
{
    // init the application
    if (!app_->init()) {
       LOG_ERR("Couldn't initialize application");
       return false;
    }

    //注册一个message handler,用于处理client访问时收到的请求,这里注册了on_message_cbk函数
    // register a message handler callback for messages sent to our service
    app_->register_message_handler(service_id, service_instance_id,
    service_method_id,
    std::bind(&hello_world_service::on_message_cbk, this,
              std::placeholders::_1));

    // register a state handler to get called back after registration at the
    // runtime was successful
    //只有对应的服务状态正常后,才会提供对应的服务。
    //因此这里监听一下状态
    app_->register_state_handler(
    std::bind(&hello_world_service::on_state_cbk, this,
              std::placeholders::_1));
    return true;
}

初始化的函数中,首先是对我们之前创建的application对象进行初始化,app_->init()这个函数主要做了如下几件事情:

  1. 加载我们在启动时指定的配置文件
  2. 加载对应的插件库
  3. 初始化routing配置

基本application对象初始化完毕,这里注册了两个回调函数,一个是on_message_cbk主要用来处理收到client的request后的事情。

还有一个函数 on_state_cbk,主要处理,相关的服务再routing中注册成功后的操作。

提供服务

Start函数

初始化完毕后,相关的回调函数也已经注册,这时候,就可以调用start函数进行启动了。

void start()
{
    // start the application and wait for the on_event callback to be called
    // this method only returns when app_->stop() is called
    app_->start();
}

hello_wrold_service的start函数比较简单,直接调用了application的start函数。

这里app_->start()回去启动对应的线程。

主要有如下的几种:

主线程(hello_world_service)

io线程(4444_io01)

maindispatch线程(4444_m_dispatch)

stop_thread线程(4444_shutdown)

Routing线程(4444_client_reg)

可以看到hello_world_service启动后,对应的线程信息。

Start()内部还会处理连接routing的操作,并建立相关与routing通信的socket,建立完成之后,会设置对应的state_type_e::ST_REGISTERED状态,并调用之前注册的回调函数on_state_cbk,执行后续操作。

这里routing线程实际上不是所有的进程都会创建的,由于在helloworld的启动配置文件中,我们指定了对应的routing进程就是hello_world_service,所以这里才会去创建对应的routing.

Offer_service函数

void on_state_cbk(vsomeip::state_type_e _state)
{
	if(_state == vsomeip::state_type_e::ST_REGISTERED)
	{
	// we are registered at the runtime and can offer our service
	// 对应提供服务
		app_->offer_service(service_id, service_instance_id);
	}
}

Offer_service操作首先会在本地进程的内存信息中查找,当前服务是否已经注册发布,如果没有,会创建对应的service info。并且当前的state是ST_REGISTERED的话,那么就会发送对应的发布服务请求给routing进程。

同时这里如果服务offer是成功的,也会去通知对应的client,来调用其on_avaliability_cbk回调函数

接收消息

void on_message_cbk(const std::shared_ptr<vsomeip::message> &_request)
{
	// Create a response based upon the request
	std::shared_ptr<vsomeip::message> resp = rtm_->create_response(_request);

	// Construct string to send back
	std::string str("Hello ");
	str.append(reinterpret_cast<const 												char*>(_request->get_payload()->get_data()),
			0, _request->get_payload()->get_length());

	// Create a payload which will be sent back to the client
	std::shared_ptr<vsomeip::payload> resp_pl = 									rtm_->create_payload();
	std::vector<vsomeip::byte_t> pl_data(str.begin(), str.end());
	res	p_pl->set_data(pl_data);
	resp->set_payload(resp_pl);

	// Send the response back
	app_->send(resp);
	// we have finished
	terminate();
}

Helloworld程序的接收消息相关的操作比较简单,主要就是在on_message_cbk中执行的.

在on_message_cbk中,可以看到入参的是完整的message信息.这里应该可以拿到完整的someip包的信息.相关的message信息我们后续再详细分析.

在on_message_cbk中其实做的事情很简单,就是接收到client发来的world字符串,然后和hello进行组合,形成helloworld,然后返回给client.

退出阶段

void stop()
{
	std::unique_lock<std::mutex> its_lock(mutex_);
	while(!stop_) {
		condition_.wait(its_lock);
	}
	std::this_thread::sleep_for(std::chrono::seconds(5));
	// Stop offering the service
	app_->stop_offer_service(service_id, service_instance_id);
	// unregister the state handler
	app_->unregister_state_handler();
	// unregister the message handler
	app_->unregister_message_handler(service_id, 							service_instance_id,
			service_method_id);
	// shutdown the applicationg
	app_->stop();
}

Helloworld的stop函数主要是在client的消息调用完之后处理了,正常我们开发这里肯定需要继续服务的,因此在工程化实现的过程当中,肯定不能在on_message中去结束服务.

这里结束函数主要就是针对的就是我们初始化阶段的那些操作,首先是stop_offer_service,然后unregister我们初始化注册的message_handler和state_handler.

最后执行app_->stop.

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值