VSOMEIP主要流程的时序

请求服务:

client应用:

​ application_impl::request_service

​ routing_manager_client::request_service (老版本是routing_manager_proxy)

​ routing_manager_client::send_request_services

​ protocol::request_service_command its_command; // 创建订阅cmd

​ local_uds_client_endpoint_impl::send // 将订阅cmd发送给routingmanagerd

routingmanagerd:

​ local_uds_server_endpoint_impl::connection::receive_cbk // UnixDomainSocket /tmp/vsomeip-0 收到应用发来的request service命令

​ routing_manager_stub::on_message

​ routing_manager_impl::request_service

​ endpoint_manager_impl::find_or_create_remote_client // 从remote_service_info_中查找远端服务的配置,创建client_endpoint

​ tcp_client_endpoint_impl::start // 启动线程进行connect操作 (创建并且打开asio socket,设置socket属性,最后async_connect)

​ udp_client_endpoint_impl::start // 同上

在vsomeip中,每一个服务只占用一个端口(TCP/UDP/BOTH),无论method还是event都在这个端口上通信。

client发给routingmanagerd的cmd中,包含了client的端的clientid

请求事件:

client应用:

​ application_impl::request_event (service, instance, event, eventgroup事件组集合, 事件类型, reliable) //事件类型event/field/select_event

​ routing_manager_client::register_event

​ routing_manager_client::send_register_event

​ protocol::register_events_command its_command; // 注册event的cmd

​ local_uds_client_endpoint_impl::send // 将注册event的cmd发送给routingmanagerd

routingmanagerd:

​ local_uds_server_endpoint_impl::connection::receive_cbk // UnixDomainSocket /tmp/vsomeip-0 收到应用发来的request event命令

​ routing_manager_stub::on_message

​ 轮询protocol::register_events_command中的每一个register event项目

​ routing_manager_impl::register_shadow_event

​ routing_manager_base::register_event //将事件和事件组注册到内部的events_ 和eventgroups_ 中

// routing_manager_base内部events_ 和eventgroups_ 的作用

primitive_types.hpp

...
typedef uint32_t message_t;
typedef uint16_t service_t;
typedef uint16_t method_t;
typedef uint16_t event_t;typedef uint16_t instance_t;
typedef uint16_t eventgroup_t;
...

event.hpp

...
class event {...
private:...// 记录了每个eventgroup有哪些本地client订阅了// 每个event可以属于一个或者多个eventgroupstd::map<eventgroup_t, std::set<client_t> > eventgroups_;...
};
...

eventgroupinfo.hpp

class eventgroupinfo {
...
private:...std::set<std::shared_ptr<event> > events_;    // 记录了该eventgroup中的所有event(event中可以找到订阅该eventgroup的client)...std::map<remote_subscription_id_t,std::shared_ptr<remote_subscription>> subscriptions_;    // 保存对其他域的服务的订阅者的信息remote_subscription_id_t id_;  // 每增加一个对其他域的服务的订阅者(非域内), id_ 加一...
};

routing_manager_base.hpp

std::map<service_t,    			// 服务IDstd::map<instance_t,    // 实例IDstd::map<event_t,   // 事件IDstd::shared_ptr<event> > > > events_;    // 事件所属的组和每个组的订阅客户端std::map<service_t,				// 服务IDstd::map<instance_t,// 实例IDstd::map<eventgroup_t, std::shared_ptr<eventgroupinfo> > > > eventgroups_;  // 事件组中的事件和每个事件的订阅者信息

订阅:

client应用:

​ application_impl::subscribe

​ routing_manager_client::subscribe

​ routing_manager_client::send_subscribe

​ protocol::subscribe_command its_command; // 订阅cmd

​ local_uds_client_endpoint_impl::send // 将订阅的cmd发送给routingmanagerd

routingmanagerd:

​ local_uds_server_endpoint_impl::connection::receive_cbk // UnixDomainSocket /tmp/vsomeip-0 收到应用发来的subscribe命令

​ routing_manager_stub::on_message

​ routing_manager_impl::subscribe

​ const client_t its_local_client = find_local_client(_service, _instance); // 获取是哪个client发布了要订阅的服务

​ // 1. 订阅的服务是当前routingmanagerd应用发布的

​ if (get_client() == its_local_client) {

​ endpoint_manager_base::find_or_create_local // 根据订阅者的clientid创建用于通信的local

​ application_impl::on_subscription // 通知application有订阅到达,是否accept (accept_cbk是传入的匿名函数)

​ routing_manager_stub::send_subscribe_ack // 接收订阅,则回复ACK

​ routing_manager_stub::send_subscribe_nack // 否则回复NACK

​ }

​ // 2. 订阅的服务不是当前routingmanagerd应用发布的

​ routing_manager_base::insert_subscription

​ if (_event != ANY_EVENT) { // subscribe to specific event

​ // 在event_中插入订阅client的订阅记录

​ } else {

​ // 在eventgroups_的每个event中插入订阅client的订阅记录

​ }

​ // 2.1 订阅的服务是域外的someip应用发布的

​ if (0 == its_local_client) { // 说明域内找不到提供该服务的ciient

​ routing_manager_impl::find_event // 查看是否有client对该event进行过register(调用request_event)

​ routing_manager_impl::handle_subscription_state //主要是看对该event的订阅是否已经有收到过ACK了

​ if (its_state->second == subscription_state_e::SUBSCRIPTION_ACKNOWLEDGED) {

​ // Subscription already acknowledged!

​ if (_client == get_client()) {

​ // 如果订阅该服务的是routingmanagerd应用自己,则直接回调

​ application_impl::on_subscription_status(_service, _instance, _eventgroup, _event, 0x0 /OK/);

​ } else if (stub_) {

​ // 如果订阅该服务的是域内的其他应用,则通过uds将ACK消息发送过去

​ routing_manager_stub::send_subscribe_ack(_client, _service, _instance, _eventgroup, _event);

​ }

​ }

​ service_discovery_impl::subscribe // 通过SD模块订阅其他域发布的待订阅service/event/eventgroup

​ subscribed_.find //查找之前是否订阅过该eventgroup

​ std::shared_ptr<subscription> its_subscription = create_subscription() // 创建新的订阅

​ subscribed_[service] [inst] [eventgroup] = its_subscription;

​ service_discovery_impl::send_subscription

​ entry_data_t its_data; //创建要订阅的eventgroup的entry (create_eventgroup_entry)

​ auto its_current_message = std::make_shared<message_impl>(); // 创建要发送的OFFER报文

​ add_entry_data(its_messages, its_data); // 将订阅的eventgroup entry添加到OFFER报文中 service_discovery_impl::serialize_and_send // 发送

​ }

​ // 2.2 订阅的服务是域内其他someip应用发布的

​ else {

​ routing_manager_stub::send_subscribe //通过UDS 发送订阅请求给发布该service/Instance的client

​ }

发布服务:

client应用:

​ application_impl::offer_service

​ routing_manager_client::offer_service // 参数中带着clientid以及service的信息

​ routing_manager_base::offer_service // 判断一下是否可以发布service (例如局域网中已经有别的client发布了相同的service/instance)

​ routing_manager_client::send_offer_service

​ protocol::offer_service_command its_offer; // 创建发布服务的cmd

​ local_uds_client_endpoint_impl::send // 将offer service的cmd发送给routingmanagerd

routingmanagerd:

​ local_uds_server_endpoint_impl::connection::receive_cbk // UnixDomainSocket /tmp/vsomeip-0 收到应用发来的offer service命令

​ routing_manager_impl::offer_service

​ routing_manager_impl::insert_offer_command // 插入OFFER队列 (个人理解用于后期定周期发送)

​ routing_manager_impl::handle_local_offer_service // 判断是否可以Offer Service (是否存在冲突),可以offer的情况下插入local_services_中

​ service_discovery_impl::offer_service // 如果collected_offers_中不存在要发布的service,则添加进去

​ service_discovery_impl::on_offer_debounce_timer_expired // debounce定时器触发,将collected_offers_的offerentry倒出来后清空

​ std::shared_ptr<message_impl> its_message(std::make_shared<message_impl>()); // 创建要发送出去的Offer报文

​ service_discovery_impl::insert_offer_entries //将要offer的所有service entry加入Offer报文

​ service_discovery_impl::insert_offer_service // 添加单个service entry (service的entry以及option,option中包含了用于通信的endpoint信息)

​ service_discovery_impl::add_entry_data

​ service_discovery_impl::send // 发送Offer报文

​ offerservice有三种冲突的情况下,会offer失败:1. local存在相同服务 2. remote发布过相同服务 3. 当前应用本次offer的服务和之前offer的服务存在冲突

处理收到的Offer报文:

routingmanagerd:

​ routing_manager_impl::on_message

​ service_discovery_impl::on_message // 需要是SD报文才会给SD模块处理

​ service_discovery_impl::process_serviceentry // 判断entry’类型是service还是eventgroup的条件是type <= 2

​ service_discovery_impl::process_offerservice_serviceentry // service entry条目中type=1 (offer Service)

​ service_discovery_impl::update_request // 如果目前处于repetition阶段,则停止对该service发送FIND报文(因为已经收到了offer了)

​ if (_received_via_mcast) { // 如果是从组播地址收到的OFFER报文

​ auto found_service = subscribed_ .find(_service); // 从 subscribed_ 成员中查找本域中是否有client对该服务中事件组的订阅

​ 更新每一条订阅记录的状态

​ ST_ACKNOWLEDGED -> ST_RESUBSCRIBING

​ 非ST_ACKNOWLEDGED -> ST_RESUBSCRIBING_NOT_ACKNOWLEDGED

​ }

​ routing_manager_impl::add_routing_info // 新增/更新serviceinfo信息到services_remote_和services_两个内部容器

​ std::shared_ptr<serviceinfo> its_info(find_service(_service, _instance)); // 判断是否收到过该service的offer

​ if (!its_info) { // 没有是收到过该service的offer

​ routing_manager_base::create_service_info // 创建新的serviceinfo信息,添加到services_以及services_remote_中

​ }

​ endpoint_manager_impl::is_remote_service_known // 判断是否在该service上创建endpoint(reliable/unreliable)

​ if (_reliable_port != ILLEGAL_PORT && !is_reliable_known) { // service提供了tcp端口,对应的endpoint没有创建

​ for (const client_t its_client : get_requesters_unlocked(

​ endpoint_manager_impl::find_or_create_remote_client // 创建和service的tcp连接

​ its_info->add_client(its_client); // 将请求该service的client添加到上面create_service_info创建的serviceinfo中

​ }

​ }

​ if (_unreliable_port != ILLEGAL_PORT && !is_unreliable_known) { // service提供了udp端口,对应的endpoint没有创建

​ // 逻辑同TCP

​ }

​ if (!_reliable_address.is_unspecified() || !_unreliable_address.is_unspecified()) {

​ // 记录每个远端地址上发布的服务信息和收到的Offer报文数量并且打印

​ }

client应用:

​ 无:

entry条目类型的枚举值: (enumeration_types.hpp)

enum class entry_type_e: uint8_t {FIND_SERVICE = 0x00,OFFER_SERVICE = 0x01,STOP_OFFER_SERVICE = 0x01,REQUEST_SERVICE = 0x2,FIND_EVENT_GROUP = 0x4,PUBLISH_EVENTGROUP = 0x5,STOP_PUBLISH_EVENTGROUP = 0x5,SUBSCRIBE_EVENTGROUP = 0x06,STOP_SUBSCRIBE_EVENTGROUP = 0x06,SUBSCRIBE_EVENTGROUP_ACK = 0x07,STOP_SUBSCRIBE_EVENTGROUP_ACK = 0x07,UNKNOWN = 0xFF
};

service_discovery_impl中保存的事件组订阅情况的类Subscription主要结构如下:

class subscription {
...
private:std::shared_ptr<endpoint> reliable_;std::shared_ptr<endpoint> unreliable_;bool tcp_connection_established_;bool udp_connection_established_;std::map<client_t, subscription_state_e> clients_; // client-> is acknowledged?  // 每个client的订阅状态std::weak_ptr<eventgroupinfo> eg_info_;    // 订阅的事件组信息
};

routing_manager_impl中保存的收到的service信息的类serviceinfo主要结构如下:

class serviceinfo {
...
private:service_t service_;instance_t instance_;major_version_t major_;minor_version_t minor_;std::shared_ptr<endpoint> reliable_;std::shared_ptr<endpoint> unreliable_;std::set<client_t> requesters_;   // 请求过该服务的本地client
};

服务可用通知(Service Aailable)

routingmanagerd:

​ client_endpoint_impl::cancel_and_connect_cbk // 作为async_connect的回调函数被调用

​ client_endpoint_impl::connect_cbk

​ endpoint_manager_impl::on_connect

​ routing_manager_impl::service_endpoint_connected

​ routing_manager_impl::on_availability

​ routing_manager_stub::on_offer_service // 通知客户端sevice avaliable

​ routing_manager_stub::inform_requesters // routing_info_entry_type_e::RIE_ADD_SERVICE_INSTANCE

​ for (auto its_client : service_requests_) { // 该连接是用于和远端service通信的,找到请求了对应service的本地client

​ routing_manager_stub::send_client_routing_info

​ protocol::routing_info_command its_command; // 发送给client的routing_info信息(包含了service信息)

​ }

client应用:

​ routing_manager_client::on_message

​ routing_manager_client::on_routing_info

​ for (const auto &e : its_command.get_entries()) { // 轮询每一个entry (号到type为RIE_ADD_SERVICE_INSTANCE的条目)

​ application_impl::on_availability // 通知application服务可用

​ }

处理订阅:

routingmanagerd:

​ service_discovery_impl::on_message

​ auto its_acknowledgement = std::make_shared<remote_subscription_ack>(_sender); //提前准备好给客户端回复的订阅ACK/NACK报文

​ service_discovery_impl::process_eventgroupentry

​ service_discovery_impl::insert_subscription_ack

​ service_discovery_impl::add_entry_data_to_remote_subscription_ack_msg

​ service_discovery_impl::send_subscription_ack

client应用:

​ 无

处理订阅ACK/NACK

routingmanagerd:

​ service_discovery_impl::on_message

​ service_discovery_impl::process_eventgroupentry(

​ if (entry_type_e::SUBSCRIBE_EVENTGROUP_ACK == its_type) { // 对于eventgroupentry类型为subscribe_ack/nack

​ service_discovery_impl::handle_eventgroup_subscription_ack/_nack (根据Entry中的TTL判断是ACK还是NACK)

​ auto found_service = subscribed_.find(_service);

​ for (…) { // 找到每一个订阅该eventgroup的client

​ found_eventgroup->second->set_state(its_client, subscription_state_e::ST_ACKNOWLEDGED); // 修改订阅状态 (ACKED)

​ routing_manager_impl::on_subscribe_ack(_client)

​ }

​ }

client应用:

发布事件:

client应用:

routingmanagerd:

发送REQUEST:

client应用:

routingmanagerd:

发送RESPONSE:

client应用:

routingmanagerd:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/62362.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【一文读懂】大语言模型

学习参考 项目教程&#xff1a;中文教程 代码仓库&#xff1a;代码地址 仓库代码目录说明&#xff1a; requirements.txt&#xff1a;官方环境下的安装依赖 notebook&#xff1a;Notebook 源代码文件 docs&#xff1a;Markdown 文档文件 figures&#xff1a;图片 data_base&…

大数据-234 离线数仓 - 异构数据源 DataX 将数据 从 HDFS 到 MySQL

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; Java篇开始了&#xff01; 目前开始更新 MyBatis&#xff0c;一起深入浅出&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff0…

鸿蒙进阶篇-Stage模型、UIAbility

“在科技的浪潮中&#xff0c;鸿蒙操作系统宛如一颗璀璨的新星&#xff0c;引领着创新的方向。作为鸿蒙开天组&#xff0c;今天我们将一同踏上鸿蒙基础的探索之旅&#xff0c;为您揭开这一神奇系统的神秘面纱。” 各位小伙伴们我们又见面了,我就是鸿蒙开天组,下面让我们进入今…

学习threejs,使用specularMap设置高光贴图

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.MeshPhongMaterial高…

一个简洁的ajax注册登录找回密码切换的前端页面

成功和失败不同颜色显示&#xff0c;纯原生代码不需要jq等第三方插件 <% Language"VBScript" CodePage"65001"%> <% Response.Charset "UTF-8" Session.CodePage "65001" Response.Addheader "Content-Type",&q…

uniapp首页样式,实现菜单导航结构

实现菜单导航结构 1.导入字体图标库需要的文件 2.修改引用路径iconfont.css 3.导入到App.vue中 <style>import url(./static/font/iconfont.css); </style>导航区域代码 VUE代码 <template><view class"home"><!-- 导航区域 --><…

解析客服知识库搭建的五个必要性

在当今竞争激烈的商业环境中&#xff0c;客服知识库的搭建已成为企业提升服务质量、优化客户体验的重要手段。一个完善的客服知识库不仅能帮助企业高效管理客户服务流程&#xff0c;还能显著提升客户满意度和忠诚度。以下是搭建客服知识库的五个必要性&#xff1a; 1. 提升服务…

淘宝Vision Pro:革新购物体验的沉浸式未来

引言 简要介绍淘宝Vision Pro版的背景,包括它在美区AppStore的发布及WWDC上的展示。阐述本文的目的:为读者提供一个全面的功能概览与设计背后的思考。设计原则 列出并简要解释5条设计原则(熟悉、直观、真实、实用、易用)。说明这些原则如何指导整个产品设计过程。核心功能详…

【CSS in Depth 2 精译_062】第 10 章 CSS 中的容器查询(@container)概述 + 10.1 容器查询的一个简单示例

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 【第十章 CSS 容器查询】 ✔️ 10.1 容器查询的一个简单示例 ✔️ 10.1.1 容器尺寸查询的用法 ✔️ 10.2 深入理解容器10.3 与容器相关的单位10.4 容器样式查询的用法10.5 本章小结 文章目录 第 10…

HCIE:详解OSPF,从基础到高级特性再到深入研究

目录 前言 一、OSPF协议基本原理 简介 基本原理 OSPF路由器类型 OSPF网络类型 OSPF报文类型和封装 OSPF邻居的建立的维护 DR和BDR的选举 伪节点 LSDB的更新 OSPF的配置 二、OSPF的高级特性 虚连接&#xff08;Virtual-Link&#xff09; OSPF的LSA和路由选择 OSPF…

think php处理 异步 url 请求 记录

1、需求 某网站 需要 AI生成音乐&#xff0c;生成mp3文件的时候需要等待&#xff0c;需要程序中实时监听mp3文件是否生成 2、用的开发框架 为php 3、文件结构 配置路由设置 Route::group(/music, function () {Route::post(/musicLyrics, AiMusic/musicLyrics);//Ai生成歌词流式…

【VRChat 改模】开发环境搭建:VCC、VRChat SDK、Unity 等环境配置

一、配置 Unity 相关 1.下载 UnityHub 下载地址&#xff1a;https://unity.com/download 安装打开后如图所示&#xff1a; 2.下载 VRChat 官方推荐版本的 Unity 跳转界面&#xff08;VRChat 官方推荐页面&#xff09;&#xff1a;https://creators.vrchat.com/sdk/upgrade/…

ollama部署bge-m3,并实现与dify平台对接

概述 这几天为了写技术博客,各种组件可谓是装了卸,卸了装,只想复现一些东西,确保你们看到的东西都是可以复现的。 (看在我这么认真的份上,求个关注啊,拜托各位观众老爷了。) 这不,为了实验在windows上docker里运行pytorch,把docker重装了。 dify也得重装: Dify基…

详细介绍HTTP与RPC:为什么有了HTTP,还需要RPC?

目录 一、HTTP 二、RPC 介绍 工作原理 核心功能 如何服务寻址 如何进行序列化和反序列化 如何网络传输 基于 TCP 协议的 RPC 调用 基于 HTTP 协议的 RPC 调用 实现方式 优点和缺点 使用场景 常见框架 示例 三、问题 问题一&#xff1a;是先有HTTP还是先有RPC&…

Lesson 10 GNN

听课&#xff08;李宏毅老师的&#xff09;笔记&#xff0c;方便梳理框架&#xff0c;以作复习之用。本节课主要讲了生成式对抗网络&#xff08;GNN&#xff09;。 目录 Generation Network as Generator 到目前为止&#xff0c;我们学习到的是类似于函数的network&#xf…

Scala入门基础(20)数据集复习拓展

一.Stack栈二.Queue 队列 一.Stack栈 Stack:栈&#xff0c;特殊的结构。它对元素的操作是在头部&#xff1a;栈顶 先进后出的队列。pop表示取出&#xff0c;push表示在栈中添加元素 二.Queue 队列 Queue 队列;先进先出.enqueue入队&#xff0c;dequeue出队。

Ubuntu20.04运行DM-VIO

目录 环境配置非ROS环境运行编译运行结果图 ROS环境参考 环境配置 Ubuntu20.04 将项目中Cmakelists.txt中C 和 opencv版本修改下 C 使用 14 opencv使用4 非ROS环境运行 编译 按照官网即可 cd dm-vio mkdir build cd build cmake .. make -j运行 DM-VIO给的命令是 bin/d…

TDengine 签约深圳综合粒子,赋能粒子研究新突破

在高能物理和粒子研究领域&#xff0c;实验装置的不断升级伴随着海量数据的产生与处理。尤其是随着大湾区综合性国家科学中心的建设步伐加快&#xff0c;深圳综合粒子设施研究院&#xff08;以下简称“研究院”&#xff09;作为承载“双区驱动”战略的重要科研机构&#xff0c;…

IDEA连接Apifox客户端

IDEA连接Apifox客户端 一、下载Apifox安装包二、IDEA配置三、配置Apifox和IDEA项目同步 一、下载Apifox安装包 Apifox官网&#xff0c;根据自己的操作系统下载对应的Apifox安装包&#xff0c;我是windows系统所以下载的是windows版。 下载 默认仅为我安装&#xff0c;点击下一…

(C语言) 8大翻译阶段

(C语言) 8大翻译阶段 文章目录 (C语言) 8大翻译阶段⭐前言&#x1f5c3;️8大阶段&#x1f5c2;️1. 字符映射&#x1f5c2;️2. 行分割&#x1f5c2;️3. 标记化&#x1f5c2;️4. 预处理&#x1f5c2;️5. 字符集映射&#x1f5c2;️6. 字符串拼接&#x1f5c2;️7. 翻译&…