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

Android 13 - Media框架(14)- OpenMax(二)

这一节我们将来解析 media.codec 这个 HIDL service 究竟提供了什么服务,服务是如何启动的。

1、main 函数

我们先来看 frameworks/av/services/mediacodec/main_codecservice.cpp:

int main(int argc __unused, char** argv)
{strcpy(argv[0], "media.codec");LOG(INFO) << "mediacodecservice starting";signal(SIGPIPE, SIG_IGN);android::ProcessState::initWithDriver("/dev/vndbinder");android::ProcessState::self()->startThreadPool();::android::hardware::configureRpcThreadpool(64, false);// Default codec servicesusing namespace ::android::hardware::media::omx::V1_0;sp<IOmx> omx = new implementation::Omx();if (omx == nullptr) {LOG(ERROR) << "Cannot create IOmx HAL service.";} else if (omx->registerAsService() != OK) {LOG(ERROR) << "Cannot register IOmx HAL service.";} else {LOG(INFO) << "IOmx HAL service created.";}sp<IOmxStore> omxStore = new implementation::OmxStore(property_get_int64("vendor.media.omx", 1) ? omx : nullptr);if (omxStore == nullptr) {LOG(ERROR) << "Cannot create IOmxStore HAL service.";} else if (omxStore->registerAsService() != OK) {LOG(ERROR) << "Cannot register IOmxStore HAL service.";}::android::hardware::joinRpcThreadpool();
}

main 函数中创建了 IOmx 和 IOmxStore 两个对象,说明这一个进程有两个服务。

我会对这里的代码有一点疑问,media.codec 这个进程作为 HIDL service 应该使用 /dev/hwbinder,main函数一开始为什么打开的是 /dev/vndbinder 呢?

观察可以看到 IOmx 会调用 registerAsService 方法,这个方法可以在 HIDL 编译生成文件中找到:

::android::status_t IOmx::registerAsService(const std::string &serviceName) {return ::android::hardware::details::registerAsServiceInternal(this, serviceName);
}

内部调用了 registerAsServiceInternal 方法将服务对象注册到了 /dev/hwbinder,至于为什么要打开 /dev/vndbinder 我猜测可能是为了给 vendor 进程调用吧…


2、IOmx

Omx 的构造函数创建了一个 OMXStore 用于加载、创建、管理所有的 OMX 组件,以及一个 MediaCodecsXmlParser 用于加载 Media 相关的 xml 配置文件。

Omx::Omx() :mStore(new OMXStore()),mParser() {(void)mParser.parseXmlFilesInSearchDirs();(void)mParser.parseXmlPath(mParser.defaultProfilingResultsXmlPath);
}

接下来对 IOmx 提供的其他服务接口做简单的功能介绍:

    Return<void> listNodes(listNodes_cb _hidl_cb) override;Return<void> allocateNode(const hidl_string& name,const sp<IOmxObserver>& observer,allocateNode_cb _hidl_cb) override;Return<void> createInputSurface(createInputSurface_cb _hidl_cb) override;// Method from hidl_death_recipientvoid serviceDied(uint64_t cookie, const wp<IBase>& who) override;// Method for OMXNodeInstancestatus_t freeNode(sp<OMXNodeInstance> const& instance);
  • listNodes:给 IOmxStore 使用,列出所有可用的组件;
  • allocateNode:根据组件名创建 OMX 组件;
  • createInputSurface:暂未使用到,后期碰到了再来记录;
  • freeNode:释放创建的 OMX 组件。

OMXStore 是 IOmx 服务的大管家,创建销毁组件最终都由 OMXStore 来完成。这里不会去了解具体的如何创建销毁的过程,重在先了解设计结构。


3、OMXStore

OMXStore 的构造函数加载了两个 lib(libstagefrighthw.so, libstagefright_softomx_plugin.so),第一个lib 是硬件平台需要实现的,也就是我们所说的硬件解码实现,第二个 lib 是Android平台提供的默认的软件编解码实现,现在它已经被移除,并且用 CCodec 来替代。

我们这一系列笔记重点要研究的是硬件编解码的框架,所以只研究 libstagefrighthw.so 的部分。

这里之所以用 dlopen 和 dlsym 加载库是因为,不是所有的平台都会实现硬件编解码库,如果用动态链接这里就会出错了。

OMXStore::OMXStore() {......addVendorPlugin();addPlatformPlugin();
}void OMXStore::addVendorPlugin() {addPlugin("libstagefrighthw.so");
}void OMXStore::addPlatformPlugin() {addPlugin("libstagefright_softomx_plugin.so");
}

在进入 OMXStore 了解之前,我们先对这部分的实现结构做一个简单了解,这样学习起来会更轻松。Android 源码中已经有了高通的 demo 实现可供我们参考,位于:

hardware/qcom/media/msm8998/libstagefrighthw
hardware/qcom/media/msm8998/mm-core/src/common

这里主要涉及了两个库,libstagefrighthw.so 已经在 OMXStore 中看到过了,还有另一个重要的库 libOmxCore.so 它实现了获取调用 OMX 服务的标准接口。

请添加图片描述

这里会由下自上来描述每一层的作用:

  1. 编解码库实现:厂商会提供多个硬件编解码实现,这些库以 OMX 开头,接下来的问题是如何使用这些库?;
  2. libOmxCore.so:所有的硬件编解码库实现都会以列表的形式存储在 libOmxCore.so 中,libOmxCore.so 库实现了 OMX 框架提供的标准接口,上层可以通过这些接口获取底层硬件编解码库的实现;当然,libOmxCore这个库的名字可以由 vendor 自己定义;
  3. libstagefrighthw.so:libstagefrighthw 对 libOmxCore 提供的接口调用进行了封装,并且提供标准接口给上层使用,这一层同样由 vendor 来实现,如果上面的 libOmxCore 名称发生变化,那么 libstagefrighthw 加载的库名也要变化;
  4. OMXStore:如果可以成功加载 libstagefrighthw.so,那么就调用它的标准接口获取底层 OMX 提供的服务细节。

3.1、addPlugin

接下来一起了解 libstagefrighthw 的加载过程:

void OMXStore::addPlugin(const char *libname) {// 1. 获取 vendor.media.omx ,如果是0则退出if (::android::base::GetIntProperty("vendor.media.omx", int64_t(1)) == 0) {return;}// 2. 加载 libstagefrighthw.sovoid *libHandle = android_load_sphal_library(libname, RTLD_NOW);if (libHandle == NULL) {return;}// 3. 获取lib 中的方法typedef OMXPluginBase *(*CreateOMXPluginFunc)();CreateOMXPluginFunc createOMXPlugin =(CreateOMXPluginFunc)dlsym(libHandle, "createOMXPlugin");if (!createOMXPlugin)createOMXPlugin = (CreateOMXPluginFunc)dlsym(libHandle, "_ZN7android15createOMXPluginEv");// 4. 调用方法创建实例OMXPluginBase *plugin = nullptr;if (createOMXPlugin) {plugin = (*createOMXPlugin)();}// 5. 存储创建的实例if (plugin) {mPlugins.push_back({ plugin, libHandle });// 6. 从实例中读取提供的服务内容addPlugin(plugin);} else {android_unload_sphal_library(libHandle);}
}
  1. 首先获取 vendor.media.omx 属性,默认是 1,如果设置了0,则硬件编解码将不会再走 OMX 一路,这应该是在为切换到 CCodec 做准备;
  2. 加载libstagefrighthw.so,dlsym 获取 createOMXPlugin 接口;
  3. 调用 createOMXPlugin 创建 OMXPluginBase 实例;
  4. 存储实例,从实例中获取提供的服务内容。

从上面的流程中我们可以知道,libstagefrighthw 需要实现 createOMXPlugin 接口,该接口会创建一个 OMXPluginBase 对象。

createOMXPlugin 接口声明位于
frameworks/native/headers/media_plugin/media/hardware/HardwareAPI.h

OMXPluginBase 声明位于 frameworks/native/headers/media_plugin/media/hardware/OMXPluginBase.h


struct OMXPluginBase {OMXPluginBase() {}virtual ~OMXPluginBase() {}// 创建组件实例virtual OMX_ERRORTYPE makeComponentInstance(const char *name,const OMX_CALLBACKTYPE *callbacks,OMX_PTR appData,OMX_COMPONENTTYPE **component) = 0;// 销毁组件实例virtual OMX_ERRORTYPE destroyComponentInstance(OMX_COMPONENTTYPE *component) = 0;// 列出组件信息virtual OMX_ERRORTYPE enumerateComponents(OMX_STRING name,size_t size,OMX_U32 index) = 0;// 获取组件 rolevirtual OMX_ERRORTYPE getRolesOfComponent(const char *name,Vector<String8> *roles) = 0;private:OMXPluginBase(const OMXPluginBase &);OMXPluginBase &operator=(const OMXPluginBase &);
};

3.2、addPlugin Inner

这里又有一个 addPlugin,但是它的功能和上面3.1节中的是完全不同的,这里的 addPlugin 参数为 OMXPluginBase,用于加载 OMX 组件信息的。

void OMXStore::addPlugin(OMXPluginBase *plugin) {Mutex::Autolock autoLock(mLock);// 获取当前设备类型,获取设备api levelbool typeTV = isTV();int firstApiLevel = getFirstApiLevel();OMX_U32 index = 0;char name[128];OMX_ERRORTYPE err;// 循环读取 OMXPluginBase 中的组件信息,传出参数为字符串while ((err = plugin->enumerateComponents(name, sizeof(name), index++)) == OMX_ErrorNone) {String8 name8(name);Vector<String8> roles;// 根据字符串再从 OMXPluginBase 解析出 roleOMX_ERRORTYPE err = plugin->getRolesOfComponent(name, &roles);if (err == OMX_ErrorNone) {bool skip = false;for (String8 role : roles) {// 根据当前的 API level 来判断是否要加载当前组件if (role.find("video_decoder") != -1 || role.find("video_encoder") != -1) {if (firstApiLevel >= __ANDROID_API_T__) {skip = true;break;} else if (!typeTV && firstApiLevel >= __ANDROID_API_S__) {skip = true;break;}}if (role.find("audio_decoder") != -1 || role.find("audio_encoder") != -1) {if (firstApiLevel >= __ANDROID_API_T__) {skip = true;break;}}}if (skip) {continue;}}// 判断是否有重复if (mPluginByComponentName.indexOfKey(name8) >= 0) {ALOGE("A component of name '%s' already exists, ignoring this one.",name8.string());continue;}mPluginByComponentName.add(name8, plugin);}
}
  1. 获取设备类型以及api level;
  2. 调用 OMXPluginBase 的方法读取组件信息(组件名称);
  3. 获取组件名称对应的 role,如果是 video 组件,并且满足 api level 高于 Android T 或者 不是电视并且 api level 高于 Android S 的条件,则不会将该组件加载到 OMXStore 当中;如果是 audio 组件并且 api level 高于 Android T,则同样不会将该组件加载到 OMXStore 当中;
  4. 否则将组件名称存储到容器当中。

从这里我们可以了解到,从 Android 13 开始要弃用 OMX 框架了,如果 vendor 还没有实现 CCodec,则需要修改这边的内容,我们切到 Android S 上来看 OMXStore 的代码,是没有这部分的判断的。

虽然说从 Android T 开始要弃用 OMX 框架了,但是我们仍然用该版本的代码来学习它。


4、QComOMXPlugin

从上面我们可以知道 OMXStore 会打开 libstagefrighthw.so,并且调用内部方法 createOMXPlugin 创建一个 OMXPluginBase 对象,接着会调用该对象的方法读取 OMX 组件信息。之前我们只看了 OMXPluginBase 的接口声明,这一小节,我们一起来了解下 OMXPluginBase 的高通实现,代码位于:
hardware/qcom/media/msm8998/libstagefrighthw/QComOMXPlugin.cpp

QComOMXPlugin::QComOMXPlugin(): mLibHandle(dlopen("libOmxCore.so", RTLD_NOW)),mInit(NULL),mDeinit(NULL),mComponentNameEnum(NULL),mGetHandle(NULL),mFreeHandle(NULL),mGetRolesOfComponentHandle(NULL) {if (mLibHandle != NULL) {mInit = (InitFunc)dlsym(mLibHandle, "OMX_Init");mDeinit = (DeinitFunc)dlsym(mLibHandle, "OMX_Deinit");mComponentNameEnum =(ComponentNameEnumFunc)dlsym(mLibHandle, "OMX_ComponentNameEnum");mGetHandle = (GetHandleFunc)dlsym(mLibHandle, "OMX_GetHandle");mFreeHandle = (FreeHandleFunc)dlsym(mLibHandle, "OMX_FreeHandle");mGetRolesOfComponentHandle =(GetRolesOfComponentFunc)dlsym(mLibHandle, "OMX_GetRolesOfComponent");if (!mInit || !mDeinit || !mComponentNameEnum || !mGetHandle ||!mFreeHandle || !mGetRolesOfComponentHandle) {dlclose(mLibHandle);mLibHandle = NULL;} else(*mInit)();}
}

QComOMXPlugin 的构造函数里打开了 libOmxCore.so,并且动态加载了内部的方法,并且在最后调用了 OMX_Init 方法。

看到这里,如果我们要实现自己的底层硬件编解码库,首先要写一个 libstagefrighthw.so,内部要包含 createOMXPlugin 方法,该方法要返回 OMXPluginBase 对象,该对象的构造函数里同样也要打开一个类似 libOmxCore.so 的库,库里面封装有 OMX_GetHandle,OMX_FreeHandle 等方法。


5、IOmxStore

我们这里不会去详细展开 IOmxStore 的内容,IOmxStore 我看到的只在一个地方有使用:在 MediaCodecList 加载时,加载 OMX 组件时会用到 IOmxStore。IOmxStore 里的信息怎么来的?

IOmx 的构造函数中有三句和 xml 相关的内容,codec 信息就是在这里被加载的:

    mParser() {(void)mParser.parseXmlFilesInSearchDirs();(void)mParser.parseXmlPath(mParser.defaultProfilingResultsXmlPath);

我们这里主要看 parseXmlFilesInSearchDirs:

    status_t parseXmlFilesInSearchDirs(const std::vector<std::string> &xmlFiles = getDefaultXmlNames(),const std::vector<std::string> &searchDirs = getDefaultSearchDirs());static std::vector<std::string> getDefaultSearchDirs() {return { "/product/etc","/odm/etc","/vendor/etc","/system/etc" };}std::vector<std::string> MediaCodecsXmlParser::getDefaultXmlNames() {static constexpr char const* prefixes[] = {"media_codecs","media_codecs_performance"};static std::vector<std::string> variants = {android::base::GetProperty("ro.media.xml_variant.codecs", ""),android::base::GetProperty("ro.media.xml_variant.codecs_performance", "")};static std::vector<std::string> names = {prefixes[0] + variants[0] + ".xml",prefixes[1] + variants[1] + ".xml",// shaping information is not currently variant specific."media_codecs_shaping.xml"};return names;
}	

可以看到默认情况下,会到 “/product/etc”, “/odm/etc”, “/vendor/etc”, “/system/etc” 这四个目录下查找 media_codecs.xml 和 media_codecs_performance.xml 以及 media_codecs_shaping.xml。

如果我们的文件名称不是使用的默认的,那么需要用属性 ro.media.xml_variant.codecs 和 ro.media.xml_variant.codecs_performance 来自定义文件名。

具体如何加载以及解析 xml 文件的,可以参考:MediaCodecsXmlParser.cpp。

我们要注意的是,IOmxStore 这里存储的所有的 codec 信息均是来自于 xml 文件,并不会从 OMX 去读取。如果 xml 文件中没有某个组件相关的配置,则无法从 MediaCodecList 中获取到该组件信息,因此也就无法创建该组件;如果 OMX某个组件的信息没有加载到 OMXStore 中,那么就算可以从 MediaCodecList 中获取到组件信息,那么也是无法创建该组件的。所以 xml 文件需要和 libOmxCore 中的内容保持一致。

相关文章:

Android 13 - Media框架(14)- OpenMax(二)

这一节我们将来解析 media.codec 这个 HIDL service 究竟提供了什么服务&#xff0c;服务是如何启动的。 1、main 函数 我们先来看 frameworks/av/services/mediacodec/main_codecservice.cpp&#xff1a; int main(int argc __unused, char** argv) {strcpy(argv[0], "…...

【Python大数据笔记_day11_Hadoop进阶之MR和YARNZooKeeper】

MR 单词统计流程 已知文件内容: hadoop hive hadoop spark hive flink hive linux hive mysql ​ input结果: k1(行偏移量) v1(每行文本内容)0 hadoop hive hadoop spark hive 30 flink hive linux hive mysql map结果:k2(split切割后的单词) v2(拼接…...

飞桨——总结PPOCRLabel中遇到的坑

操作系统&#xff1a;win10 python环境&#xff1a;python3.9 paddleocr项目版本&#xff1a;2.7 1.报错&#xff1a;ModuleNotFoundError: No module named Polygon&#xff08;已解决&#xff09; 已解决所以没有复现报错内容 尝试方法一&#xff1a;直接使用pip命令安装&…...

LeetCode(30)长度最小的子数组【滑动窗口】【中等】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 长度最小的子数组 1.题目 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度。如果…...

Niushop 开源商城 v5.1.7:支持PC、手机、小程序和APP多端电商的源码

Niushop 系统是一款基于 ThinkPHP6 开发的电商系统&#xff0c;提供了丰富的功能和完善的商品机制。该系统支持普通商品和虚拟商品&#xff0c;并且针对虚拟商品还提供了完善的核销机制。同时&#xff0c;它也支持新时代的商业模式&#xff0c;如拼团、分销和多门店砍价等营销活…...

Navmesh 寻路

用cocos2dx引擎简单实现了一下navmesh的多边形划分&#xff0c;然后基于划分多边形的a*寻路。以及路径拐点优化算法 用cocos主要是方便使用一些渲染接口和定时器。重点是实现的原理。 首先画了一个带有孔洞的多边形 //多边形的顶点数据Vec2(100, 100),Vec2(300, 200),Vec2(50…...

YOLOv5 分类模型 数据集加载 3

YOLOv5 分类模型 数据集加载 3 自定义类别 flyfish YOLOv5 分类模型 数据集加载 1 样本处理 YOLOv5 分类模型 数据集加载 2 切片处理 YOLOv5 分类模型的预处理&#xff08;1&#xff09; Resize 和 CenterCrop YOLOv5 分类模型的预处理&#xff08;2&#xff09;ToTensor 和 …...

『亚马逊云科技产品测评』活动征文|AWS 存储产品类别及其适用场景详细说明

授权声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 Developer Centre, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道 目录 前言、AWS 存储产品类别 1、Amazon Elastic Block Store (EBS) …...

Mac | Vmware Fusion | 分辨率自动还原问题解决

1. 问题 Mac的Vmware Fusion在使用Windows10虚拟机时&#xff0c;默认显示器配置如下&#xff1a; 开机进入系统并变更默认分辨率后&#xff0c;只要被 ⌘Tab 切换分辨率就会还原到默认&#xff0c;非常影响体验。 2. 解决方式 调整 设置 -> 显示器 -> 虚拟机分辨率…...

SQL知多少?这篇文章让你从小白到入门

个人网站 本文首发公众号小肖学数据分析 SQL&#xff08;Structured Query Language&#xff09;是一种用于管理和处理关系型数据库的编程语言。 对于想要成为数据分析师、数据库管理员或者Web开发人员的小白来说&#xff0c;学习SQL是一个很好的起点。 本文将为你提供一个…...

centos7安装MySQL—以MySQL5.7.30为例

centos7安装MySQL—以MySQL5.7.30为例 本文以MySQL5.7.30为例。 官网下载 进入MySQL官网&#xff1a;https://www.mysql.com/ 点击DOWNLOADS 点击链接&#xff1b; 点击如上链接&#xff1a; 选择对应版本&#xff1a; 点击下载。 安装 将下载后的安装包上传到/usr/local下…...

3.计算机网络补充

2.5 HTTPS 数字签名&#xff1a;发送端将消息使⽤ hash 函数⽣成摘要&#xff0c;并使⽤私钥加密后得到“数字签名”&#xff0c;并将其附在消息之后。接收端使⽤公钥对“数字签名”解密&#xff0c;确认发送端身份&#xff0c;之后对消息使⽤ hash 函数处理并与接收到的摘要对…...

【云原生】Spring Cloud Alibaba 之 Gateway 服务网关实战开发

目录 一、什么是网关 ⛅网关的实现原理 二、Gateway 与 Zuul 的区别&#xff1f; 三、Gateway 服务网关 快速入门 ⛄需求 ⏳项目搭建 ✅启动测试 四、Gateway 断言工厂 五、Gateway 过滤器 ⛽过滤器工厂 ♨️全局过滤器 六、源码地址 ⛵小结 一、什么是网关 Spri…...

opencv-直方图均衡化

直方图均衡化是一种用于增强图像对比度的图像处理技术。它通过调整图像的灰度级别分布&#xff0c;使得图像中各个灰度级别的像素分布更均匀&#xff0c;从而提高图像的对比度。 在OpenCV中&#xff0c;你可以使用cv2.equalizeHist()函数来进行直方图均衡化。 以下是一个简单…...

npm install安装报错

npm WARN notsup Not compatible with your version of node/npm: v-click-outside-x3.7.1 npm ERR! Error while executing: npm ERR! /usr/bin/git ls-remote -h -t ssh://gitgithub.com/itargaryen/simple-hotkeys.git 解决办法1&#xff1a;&#xff08;没有解决我的问题…...

Spring Boot创建和使用(重要)

Spring的诞生是为了简化Java程序开发的&#xff01; Spring Boot的诞生是为了简化Spring程序开发的&#xff01; Spring Boot就是Spring框架的脚手架&#xff0c;为了快速开发Spring框架而诞生的&#xff01;&#xff01; Spring Boot的优点&#xff1a; 快速集成框架&#x…...

python 基于gdal,richdem,pysheds实现 实现洼填、D8流向,汇流累计量计算,河网连接,分水岭及其水文分析与斜坡单元生成

python gdal实现水文分析算法及其斜坡单元生成 实现洼填、D8流向,汇流累计量计算,河网连接,分水岭 # utf-8 import richdem as rdre from River import * from pysheds.grid import Grid import time from time import time,sleep import numpy as np from osgeo import g…...

帝国cms开发一个泛知识类的小程序的历程记录

#帝国cms小程序# 要开发一个泛知识类的小程序&#xff0c;要解决以下几个问题。 1。知识内容的分类。 2。知识内容的内容展示。 3。知识内容的价格设置。 4。用户体系&#xff0c;为简化用户的操作&#xff0c;在用户进行下载的时候&#xff0c;请用户输入手机号&#xff…...

Kafka官方生产者和消费者脚本简单使用

问题 怎样使用Kafka官方生产者和消费者脚本进行消费生产和消费?这里假设已经下载了kafka官方文件,并已经解压. 生产者配置文件 producer_hr.properties bootstrap.servers10.xx.xx.xxx:9092,10.xx.xx.xxx:9092,10.xx.xx.xxx:9092 compression.typenone security.protocolS…...

如何开发干洗店用的小程序

洗护行业现在都开始往线上的方向发展了&#xff0c;越来越多的干洗店都推出了上门取送服务&#xff0c;那么就需要开发一个干洗店专用的小程序去作为用户和商家的桥梁&#xff0c;这样的小程序该如何开发呢&#xff1f; 一、功能设计&#xff1a;根据干洗店的业务需求和小程序的…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统&#xff1a;Ubuntu 24.04 LTS (WSL2)架构&#xff1a;x86_64 (GNU/Linux)Rust 版本&#xff1a;rustc 1.87.0 (2025-05-09)Cargo 版本&#xff1a;cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...