当前位置: 首页 > news >正文

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:

相关文章:

VSOMEIP主要流程的时序

请求服务: client应用&#xff1a; ​ application_impl::request_service ​ routing_manager_client::request_service (老版本是routing_manager_proxy) ​ routing_manager_client::send_request_services ​ protocol::request_service_command its_command; // 创建…...

右值引用和移动语义:

C 右值引用和移动语义详解 在 C 的发展历程中&#xff0c;右值引用和移动语义的引入带来了显著的性能提升和编程灵活性。本文将深入探讨右值引用和移动语义的概念、用法以及重要性。 一、引言 C 作为一门高效的编程语言&#xff0c;一直在不断演进以满足现代软件编程的需求。…...

经纬高LLA转地心地固ECEF坐标,公式,代码

经纬高转地心地固的目的 坐标系转换是gis或者slam系统常见操作。GNSS获取的一般是经纬高&#xff0c;经纬高在slam系统里无法应用&#xff0c;slam系统一般是xyz互相垂直的笛卡尔坐标系&#xff0c;所以需要把GNSS的经纬高转到直角坐标系地心地固ECEF或者高斯投影GKP。 划重点…...

VUE前端实现天爱滑块验证码--详细教程

第一步&#xff1a; Git地址&#xff1a;tianai-captcha-demo: 滑块验证码demo 找到目录 src/main/resources/static,拷贝 static 并改名为 tac 即可。 第二步&#xff1a; 将改为 tac 的文件&#xff0c;放进项目根目录中&#xff0c;如下图&#xff1a; 第三步&#xff1…...

【链表】【删除节点】【刷题笔记】【灵神题单】

237.删除链表的节点 链表删除节点的本质是不用删除&#xff0c;只需要操作指针&#xff0c;跳过需要删除的节点&#xff0c;指向下下一个节点即可&#xff01; 删除某个节点&#xff0c;但是不知道这个节点的前一个节点&#xff0c;也不知道头节点&#xff01;摘自力扣评论区…...

springboot339javaweb的新能源充电系统pf(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 题目&#xff1a;新能源充电系统的设计与实现 摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解…...

【嵌入式——QT】QT制作安装包

第一步 QT程序写好之后&#xff0c;编译release版本 第二步 拿到release生成的.exe文件 第三步 新建文件夹deploy 第四步 将.exe文件复制到deploy目录下 第五步 在该目录下输入cmd指令&#xff0c;回车 第六步 在打开的命令窗口下输入 windeployqt TegNetCom_1.0.…...

python的文件操作练习

文件操作&#xff1a;成绩统计 有一个文件grades.txt&#xff0c;文件内容是每行一个学生的成绩&#xff08;格式&#xff1a;姓名,成绩&#xff09;。要求&#xff1a; 读取文件内容&#xff0c;统计所有学生的平均成绩&#xff1b; 将不及格&#xff08;<60分&#xff09…...

jQuery九宫格抽奖,php处理抽奖信息

功能介绍 jQuery九宫格抽奖是一种基于jQuery库的前端抽奖效果。通过九宫格的形式展示抽奖项&#xff0c;用户点击抽奖按钮后&#xff0c;九宫格开始旋转&#xff0c;最终停在一个随机位置上&#xff0c;此位置对应的抽奖项为用户的中奖结果。 本文实现九宫格的步骤为&#xf…...

2024年一级建造师考试成绩,即将公布!

一级建造师考试成绩一般在考试结束后3个月左右的时间公布&#xff01; 根据官方通知&#xff0c;重庆、江苏、青海、江西、云南、湖南、福建、北京、山西、黑龙江等地在今年一建报名通知里提到&#xff1a;2024年一级建造师考试成绩预计于2024年12月上旬公布。考生可在这个时间…...

M4V 视频是一种什么格式?如何把 M4V 转为 MP4 格式?

M4V 是一种视频文件格式&#xff0c;主要由苹果公司用于其产品和服务中&#xff0c;如 iTunes Store 上的电影和电视节目。这种格式可以包含受版权保护的内容&#xff0c;并且通常与苹果的 DRM&#xff08;数字版权管理&#xff09;技术结合使用&#xff0c;以限制内容的复制和…...

Leetcode 每日一题 104.二叉树的最大深度

目录 问题描述 示例 示例 1&#xff1a; 示例 2&#xff1a; 约束条件 题解 方法一&#xff1a;广度优先搜索&#xff08;BFS&#xff09; 步骤 代码实现 方法二&#xff1a;递归 步骤 代码实现 结论 问题描述 给定一个二叉树 root&#xff0c;我们需要返回其最大…...

文件上传漏洞:你的网站安全吗?

文章目录 文件上传漏洞攻击方式&#xff1a;0x01绕过前端限制0x02黑名单绕过1.特殊解析后缀绕过2..htaccess解析绕过3.大小写绕过4.点绕过5.空格绕过6.::$DATA绕过7.配合中间件解析漏洞8.双后缀名绕过9.短标签绕过 0x03白名单绕过1.MIME绕过(Content-Type绕过)2.%00截断3.0x00截…...

AWS账号提额

Lightsail提额 控制台右上角&#xff0c;用户名点开&#xff0c;选择Service Quotas 在导航栏中AWS服务中找到lightsail点进去 在搜索框搜索instance找到相应的实例类型申请配额 4.根据自己的需求选择要提额的地区 5.根据需求来提升配额数量,提升小额配额等大约1小时生效 Ligh…...

电子应用设计方案-29:智能云炒菜系统方案设计

智能云炒菜系统方案设计 一、系统概述 本智能云炒菜系统旨在为用户提供便捷、高效、个性化的烹饪体验&#xff0c;结合云技术实现远程控制、食谱分享、智能烹饪流程优化等功能。 二、系统组成 1. 炒菜锅主体 - 高品质不粘锅内胆&#xff0c;易于清洁和维护。 - 加热装置&#x…...

腾讯rapidJson使用例子

只需要把库的头文件拿下来加入项目中使用就行&#xff0c;我是以二进制文件存储内容并解析&#xff1a; #include <iostream> #include <fstream> #include <string> #include "rapidjson/document.h" #include "rapidjson/error/en.h"…...

UE5_CommonUI简单使用(2)

上篇我是简单写了一下CommonUI使用的初始设置以及Common Activatable Widget和Common Activatable Widget Stack以及Common 控件Style以及鼠标控制的一些内容,这些对于了解UMG的朋友来说没什么难度,唯一需要注意的就是Common Activatable Widget Stack堆栈管理只能是用来管理…...

探讨播客的生态系统

最近对播客发生了兴趣&#xff0c;从而引起了对播客背后的技术&#xff0c;生态的关注。本文谈谈播客背后的技术生态系统。 播客很简单 播客&#xff08;podcast&#xff09;本质上就是以语音的方式发布信息。它和博客非常类似。如果将CSDN 网站上的文字加一个语音播报。CSDN …...

淘宝架构演化

基本功能 LAMP&#xff08;LinuxApacheMySQLPHP&#xff09;标准架构&#xff0c;初期采用拿来主义&#xff0c;只具备基本功能。 数据库&#xff1a;读写分离&#xff0c;MyISAM存储引擎 2003年5月—2004年1月 存储瓶颈 mysql达到访问瓶颈&#xff0c;升级成oracle&#x…...

软通动力携子公司鸿湖万联、软通教育助阵首届鸿蒙生态大会成功举办

11月23日中国深圳&#xff0c;首届鸿蒙生态大会上&#xff0c;软通动力及软通动力子公司鸿湖万联作为全球智慧物联网联盟&#xff08;GIIC&#xff09;理事单位、鸿蒙生态服务&#xff08;深圳&#xff09;有限公司战略合作伙伴&#xff0c;联合软通教育深度参与了大会多项重磅…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法&#xff0c;当前调用一个医疗行业的AI识别算法后返回…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...