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

银河麒麟桌面版包管理器(二)

以下内容摘自《银河麒麟操作系统进阶应用》一书

APT包管理器

APT是Debian及其派生系统的包管理器,构建在dpkg之上,以其强大的依赖性处理能力和丰富的软件仓库而闻名。APT具有自动解决依赖关系、提供易于使用的命令行工具(如apt-get、apt-cache等),以及稳定的软件更新机制等优点。

尽管APT极大地简化了软件管理过程,但是它也面临着一些挑战和限制。例如,APT的软件仓库可能不包含某些特定的或最新的软件包,这时用户可能需要添加第三方仓库或下载.deb包手动安装。现在,APT已经经过改造,可以在支持rpm(另外一种流行的Linux安装包格式)的系统上用来管理rpm包。

APT配置文件

APT包管理器的配置和管理数据大多存储在/etc/apt/目录下,该目录包含了多个配置文件和子目录,它们控制了APT的行为,包括软件源的位置、优先级规则等。理解/etc/apt/目录的结构及其包含的文件对于高效使用APT有很大帮助。

图35是ARM64架构的银河麒麟桌面版/etc/apt目录结构(目录下的具体文件会因不同架构不同版本有所不同),在对该目录进行详细解析前,需要了解APT配置文件的语法格式。

1. APT配置文件基本语法

APT配置文件的基本语法规则如下所述。

  • 注释:以 // 或 # 开头的行被视为注释。
  • 指令:指令以关键字开始,后跟一系列参数。参数可以是布尔值(True/False)、整数、字符串(通常需要用双引号括起来)、列表(使用 { } 包围,并用逗号分隔)。
  • 作用域:配置项可以具有作用域,使用点“.”来分隔不同的层级。

/etc/apt/目录及子目录下的配置文件按文件名的“字母数字”的升序依次被解析。

2. /etc/apt/apt.conf.d/目录解析

/etc/apt/apt.conf.d/目录中通常包含多个配置文件,每个文件可以包含一条或多条配置指令,用于修改APT的默认行为或添加新功能。这种分散的配置文件结构使得管理单个配置更加简单,同时避免了单一大文件可能带来的混乱。

在设置APT的代理服务器时,可以在该目录下创建配置文件,指定APT使用的代理信息,如创建一个名为01proxy的文件,并添加如下内容:

Acquire::http::Proxy "http://your-proxy-address:port";

Acquire::https::Proxy "http://your-proxy-address:port";

现在很多代理软件可以同时支持HTTP和HTTPS协议,一般HTTP和HTTPS填写同样的IP地址(域名)和端口即可。该目录下的其他文件一般无须修改。

3. /etc/apt/sources.list文件解析

/etc/apt/sources.list文件是APT配置的核心部分,它指定了APT获取的包信息和包的位置,即软件源。这些软件源可以是网络上的服务器,也可以是本地文件系统上的目录。sources.list文件内容有两种语法格式:一种是传统的单行语法格式,另一种是较新的Deb822语法格式。

(1)单行语法格式。

符合单行语法格式时,在以.list结尾的文件中,每个软件源占据一行。银河麒麟桌面版内置的/etc/apt/sources.list内容如下,以此为例进行阐述。

deb http://archive.***.cn/kylin/KYLIN-ALL 10.1 main restricted universe multiverse

deb http://archive.***.cn/kylin/KYLIN-ALL 10.1-2303-updates main universe multiverse restricted

deb http://archive2.***.cn/deb/kylin/production/PART-V10-SP1/custom/partner/V10-SP1 default all

单个条目不能连续到多行。.list文件中的空行被忽略,任何位置的“#”字符后面部分是注释。sources.list每行内容按照下面的语法格式组织。

类型 [选项]  URI 分发版 [组件1] [组件2] [...]

  • 类型:指定软件源的类型,通常为deb(二进制包)或deb-src(源代码包)。
  • [选项]:(可选)用于指定软件源的选项,多个选项间使用逗号“,”分隔。常见的选项如下所述。
  • arch=<architecture>:指定支持的架构,例如AMD64、i386、ARM64等。不支持同时指定多个CPU架构。每个软件源条目只能指定一个架构。要支持多个架构,需要为每个架构单独定义一个条目。
  • trusted=yes:表示信任该源,不会进行GPG签名验证。
  • allow-insecure=yes:允许使用不安全的HTTP源(非HTTPS)。
  • default-release=<release>:指定默认的发布版本。
  • URI:指定软件源的URI(统一资源标识符)。URI是一种字符串,可以是具体的资源(如网页、文件)或抽象的资源(如概念、服务)。一个完整的URI通常由以下几个部分组成。
  • 方案(Scheme):指定资源的访问协议,如HTTP、HTTPS、FTP等。
  • 权限(Authority):包括用户信息、主机名和端口号,通常以双斜杠//开头。
  • 路径(Path):指定资源在服务器上的位置。
  • 查询(Query):(可选)提供额外的参数,通常用于动态页面。
  • 片段(Fragment):(可选)指定资源内的某个位置或部分。

例如在http://archive.***.cn/kylin/KYLIN-ALL这个URI中,http是方案,archive.***.cn是权限(包含了主机名archive.***.cn和省略的端口号80),/kylin/KYLIN-ALL是路径。

  • 分发版:指定特定的分发版名,如10.1、10.1-2303-updates等。
  • 组件:指软件库分类,如main、restricted、universe、multiverse。
  • main:表示官方支持的,并且完全遵循自由软件准则的软件包。
  • restricted:表示官方支持的,但不完全遵循自由软件准则的软件包。
  • universe:表示由社区维护的开源软件,不保证安全更新和维护。
  • multiverse:包含可能受到法律或版权问题限制的软件包。这些软件可能是非自由或专有的,包括一些受版权保护的软件、游戏、字体等。

上面将单行语法格式拆开了详细讲解,看似复杂,但无论是“http://archive.***.cn/kylin/ KYLIN-ALL 10.1 main restricted universe multiverse”,还是“http://archive.***.cn/kylin/KYLIN- ALL 10.1-2303-updates main universe multiverse restricted”最终总是要和服务器端的文件目录结构一一对应的。图36是软件仓库服务器端的文件目录结构,通过该图可以比较直观地理解单行语法格式中各个组成部分的相对关系。

单行语法格式的优点是,当前所有APT版本都支持,内容相对紧凑、容易人类解析。缺点是不便机器解析,因为其包括了多个部分,每个部分都有多个变种。为了解决单行语法格式机器解析不便的问题,推出了Deb822语法格式。

(2)Deb822语法格式。

对于Deb822语法格式,每个文件都需要.sources作为文件扩展名,每个软件源都在单个“配置节”中进行配置,每行明确描述源的功能。大多数选项还允许配置值列表,可以在单个软件源中定义多个镜像(Mirror)或多个套件。也就是说,Deb822格式表达能力更强,Deb822格式对APT软件的版本有要求,APT v1.1以后的版本才支持。有个别Linux发行版的最新版,例如Ubuntu 24.04的APT软件源已默认采用了Deb822格式。Deb822格式的软件源形式如下(包含了两个配置节):

Enabled: yes

Types: deb deb-src

URIs: http://***.com/ubuntu

Suites: disco disco-updates disco-security disco-backports

Components: main universe multiverse restricted

X-Repolib-Name: Pop!_OS PPA

Enabled: yes

Types: deb

URIs: http://ppa.***.net/system76/pop/ubuntu

Suites: disco

Components: main

4. /etc/apt/sources.list.d/目录解析

/etc/apt/sources.list.d/目录放置第三方额外的软件源,而不是添加到sources.list文件中。这使得管理额外软件源更加灵活。自定义源的添加方法如下:创建一个以.list为扩展名的文件,将其放置在sources.list.d/目录下,文件格式与sources.list条目格式相同。

5. /etc/apt/preferences.d/目录解析

与sources.list.d目录类似,preferences.d目录允许用户将软件包优先级配置分散到单独的文件中,以便更好地组织和管理。该目录下的preferences文件允许用户自定义包的优先级,这对于混合使用多个软件源、避免自动更新到不稳定版本或者解决依赖性问题非常有用。

文件内容语法如下所示。

Package: 包名

Pin: Pin规则

Pin-Priority: 优先级

  • 包名:可以是具体的包名,也可以用通配符*表示所有包。
  • Pin字段定义了包的来源或特征。常见的Pin规则如下所述。
  • release:指定发布版本。
  • origin:指定包来源的主机名。
  • codename:指定发布代码名。
  • archive:指定发布仓库(例如stable、testing)。
  • version:指定包的版本。
  • label:指定包的标签。
  • 优先级:整数值,APT根据这个值来决定包的安装或升级优先级。已安装软件的默认优先级通常是1000。
  • 大于1000:APT将会强制安装该版本,即使会导致系统损坏。
  • 100~1000:APT将尝试安装指定版本,除非有特定版本已被安装。
  • 0~100:APT不会自动安装该版本,但可以手动安装。
  • 负值:APT将完全忽略该版本。

下面通过几个例子展示该目录下配置文件的用法。

(1)例1:优先使用特定版本的包。

Package: mypackage

Pin: version 1.2.3

Pin-Priority: 1001

这将强制安装版本1.2.3的mypackage,即使有其他更新版本。

(2)例2:优先使用来自特定来源的包。

Package: *

Pin: origin "archive.ubuntu.com"

Pin-Priority: 700

这将优先从archive.ubuntu.com安装所有包。

(3)降低testing版软件包的优先级。

Package: *

Pin: release a=testing

Pin-Priority: 50

这将降低testing仓库中所有包的优先级,除非没有其他候选项。

银河麒麟桌面版/etc/apt/preferences.d/目录下有archive1.pref ~ archive4.pref四个文件,使用命令cat /etc/apt/preferences.d/*可同时查看这几个文件的内容(如图37所示)。

6. /etc/apt/trusted.gpg.d目录解析

原先用于存储系统信任GPG密钥的文件/etc/apt/trusted.gpg已被废弃,现在建议将软件源的GPG密钥存储在/etc/apt/trusted.gpg.d目录下的单独文件中,以提高系统的安全性。GPG密钥用于APT验证从不同软件源下载的软件包的真实性。

APT使用/etc/apt/trusted.gpg.d目录中的GPG密钥来验证软件包的方式如下所述。

  • 软件包签名验证:当APT下载软件包时,软件包会附带数字签名。APT会使用/etc/apt/trusted.gpg.d目录中的GPG密钥来验证这些签名的真实性。
  • 密钥匹配:APT会检查软件包签名中使用的密钥是否存在于/etc/apt/trusted.gpg.d目录中,如果存在匹配的密钥,则软件包被视为受信任。

通过验证软件包的签名,APT可以确保软件包在传输过程中没有被篡改或损坏。如果软件包的签名无法通过GPG密钥验证,APT就会发出警告并拒绝安装该软件包。

APT主要命令和操作

APT包管理器主要由apt-get、apt-cache、apt-mark等几个命令行工具组成,如图38所示。APT可以智能地从安装来源下载最新版本的软件并且安装,而无须在安装后重启电脑(除更新系统内核外)。

图38  银河麒麟系统中以apt开头的命令行工具

APT中的软件包有三种关联性:依赖项、建议项和推荐项。

  • 依赖项:这些是必须安装的软件包,以确保目标软件包能够正常运行。
  • 建议项:这些是软件包维护者认为大多数用户在安装目标软件包时也应该安装的软件包,但不是必需的。
  • 推荐项:这些是与目标软件包相关的软件包,可以增强其功能,也不是必需的。

(1)apt命令。

apt命令用法如表35所示。

表35  apt命令用法示例

命    令

解    释

apt list --installed

apt list --upgradable

apt list nginx*

列出已安装的包

列出可升级的包

列出所有以nginx开头的包

apt search nginx

apt search nginx --names-only

apt search ^python

apt search python$

搜索软件包名称或描述中包含nginx的所有包

仅搜索软件包名称中包含nginx的所有包

使用正则表达式搜索以“python”开头的软件包名称

使用正则表达式搜索以“python”结尾的软件包名称

apt show nginx

显示一个包的详细信息,如版本、依赖关系等

apt install nginx

apt install nginx --download-only

apt install nginx --simulate

apt install --reinstall nginx

apt install --install-suggests nginx

apt install git=1:2.45.2

正常安装软件包,自动解决依赖关系

仅下载指定包,不安装

模拟安装过程,不会实际安装包

重新安装指定的软件包

同时安装建议的软件包

安装指定版本的git

apt reinstall nginx

重新安装指定的软件包

apt satisfy nginx

apt satisfy 'nginx>=1.14'

检查并安装满足指定软件包依赖性的包

确保安装的nginx版本至少为1.14

apt remove nginx

apt remove nginx --purge

移除指定的软件包,但不删除配置文件

删除软件包及其相关的配置文件

apt autoremove

apt autoremove --purge

自动移除不再需要的包

--purge选项同时删除配置文件

apt update

更新软件包列表,从而知道有哪些可用的更新

apt upgrade

apt upgrade nginx

升级所有可升级的包或指定包

仅升级nginx包

apt full-upgrade

完全升级,可能会移除某些包以满足依赖关系

apt-mark hold nginx

apt-mark unhold nginx

nginx无法被安装、升级或卸载

恢复nginx可供更新

(2)apt-get命令。

apt-get命令包含而apt命令不包含的子命令如表36所示。

表36  apt-get相比apt的差异部分

命    令

解    释

apt-get build-dep <package>

安装构建软件包所需的构建依赖项

apt-get build-dep --no-install-
recommends <package>

安装构建依赖但跳过推荐包

apt-get check

更新缓存并检查是否有损坏的依赖

apt-get dselect-upgrade

使用dselect的结果进行升级操作

apt-get purge <package>

删除包含配置文件的软件包

apt-get purge --auto-remove <package>

删除包含配置文件的软件及其依赖

apt-get source <package>

下载指定包的源代码

apt-get source --compile <package>

下载源代码,编译并安装

apt-get download <package>

仅下载指定包而非安装

apt-get changelog <package>

下载指定软件包,并显示其变更日志

apt-get clean

清空整个/var/cache/apt/archives/目录,删除所有缓存的.deb文件

apt-get autoclean

只删除/var/cache/apt/archives/下软件包的旧版本。与clean命令相比,autoclean更加保守,它会保留可能仍然有用的包文件

(3)apt-cache命令。

apt-cache命令用法如表37所示。

表37  apt-cache命令用法

命    令

解    释

apt-cache madison <package>

显示软件包<package>在各软件源上的版本

apt-cache show <package>

显示软件包<package>所有可用版本的详细信息

apt-cache show --no-all-versions <package>

显示<package>在当前系统上可安装的最新版本的详细信息,而非所有版本

apt-cache search keyword

在包描述中搜索含有keyword的包

apt-cache search --names-only keyword

仅在包名中搜索keyword,不搜索描述

apt-cache search --full keyword

显示包含keyword的包的完整记录

apt-cache depends <package>

显示软件包<package>的依赖关系

apt-cache depends --recurse <package>

递归显示软件包<package>的依赖关系

apt-cache rdepends <package>

显示哪些包依赖软件包<package> 

apt-cache rdepends --installed <package>

仅显示已安装的包依赖软件包<package> 

apt-cache pkgnames

列出APT数据库中所有包的名称

apt-cache pkgnames <prefix>

列出APT数据库中以prefix为前缀的包名

apt-cache policy

显示已安装软件包的版本和可用版本

apt-cache policy <package>

显示特定软件包<package>的版本和来源优先权信息

apt-cache dump

打印APT缓存中所有包的详细信息

apt-cache dumpavail

打印可用的所有包列表信息,通常用于帮助调试

apt-cache unmet

显示具有未满足依赖关系的包

apt-cache unmet --auto

仅显示可能会被apt-get autoremove删除的包的未满足依赖信息

apt-cache stats

显示APT缓存的统计信息

apt-cache showpkg <package>

显示软件包<package>的所有可用版本及其依赖关系

APT离线使用

在离线环境下使用apt命令安装软件包,需要提前下载所需的软件包及其依赖项,并将它们传输到目标系统。要求下载软件包的计算机系统架构最好与离线环境下的目标计算机系统架构完全一致。

1. 方法1:使用apt-offline辅助工具

apt-offline是一个专门用于离线管理APT软件包的软件工具。它允许在离线系统上生成请求文件,然后在有网络连接的系统上下载所需的包,最后将下载的包回传到离线系统进行安装。

(1)在离线系统上生成请求文件。

安装apt-offline:

sudo apt-get install apt-offline

生成请求文件:

sudo apt-offline set ./apt-offline.sig

在当前路径下,生成一个名为apt-offline.sig的请求文件,包含了当前系统上所有需要更新或安装的软件包信息。

(2)在有网络连接的计算机上下载包。

将请求文件传输到有网络连接的计算机上,使用apt-offline下载所需的软件包:

sudo apt-offline get ./apt-offline.sig --bundle ./apt-offline.zip

这将下载所有需要的软件包,并将它们打包成为apt-offline.zip文件。

(3)在离线计算机上安装下载的软件包。

首先将下载的apt-offline.zip文件传回离线计算机,然后在离线计算机上,使用apt-offline安装下载的软件包:

sudo apt-offline install /path/to/apt-offline.zip

2. 方法2:手动下载和安装软件

如果不使用apt-offline,也可以手动下载和安装所需的软件包及其依赖项。

(1)在有网络连接的计算机上下载软件包。

在有网络连接的系统上,使用apt-get download下载所需的软件包及其依赖项。例如,要下载vim这个软件包:

sudo apt-get download $(sudo apt-cache depends --recurse --no-recommends --no-suggests --no-conflicts --no-breaks --no-replaces --no-enhances vim | grep "^\w" | sort -u)

这将下载vim及其依赖项的.deb文件,然后将所有下载的.deb文件打包成一个压缩文件或使用其他方式传输到离线计算机。

(2)在离线计算机上安装软件包。

将下载的.deb文件传回离线计算机,然后在离线计算机上,进入.deb文件所在目录,使用dpkg安装当前目录下的所有.deb文件。例如:

sudo dpkg -i ./*.deb

如果有依赖关系问题,可以使用apt-get -f install来修复依赖关系:

sudo apt-get -f install

3. 方法3:利用缓存的deb包搭建软件源

当使用APT安装或更新软件包时,APT会将下载的.deb软件包存放在/var/cache/apt/archives/目录下。如果需要重新安装软件包,APT就可以直接使用这个目录中的缓存文件,无须再次从网络下载,从而节省带宽,加快安装速度。

可以将这些缓存的软件包制作成APT可以使用的软件源,复制到离线环境后使用。具体步骤如下:

(1)在联网计算机上,将/var/cache/apt/archives/目录下的deb包复制到新的文件夹中,比如/home/<username>/repository/。

mkdir ~/repository/

cp /var/cache/apt/archives/*.deb ~/repository/

(2)生成压缩版的Packages.gz文件,Packages.gz文件包含了当前目录中的所有.deb软件包的元数据,包括软件包名称、版本、依赖关系等信息。这个文件是APT识别软件源所必需的。

cd ~/repository

sudo dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz

(3)将联网计算机上的目录~/repository/复制到离线环境。

(4)在离线计算机上,编辑sources.list文件,将软件源添加到其中:

deb [trusted=yes] file:/home/<username>/repository/ /       # 最后的“/”不可省略

请将上面file:后面的路径修改为repository实际存放路径。上面这一行内容的最后是“/”,表示该软件源不特定于任何发行版或组件,这样APT就会尝试从这个源中获取所有可用的软件包。

(5)重新加载软件包索引:

sudo apt update

通过以上步骤,就可以利用/var/cache/apt/archives/下的deb包构建自己的软件源了。

4. 方法4:使用系统安装光盘(或系统安装光盘文件)搭建本地源

通常Linux发行版是可以将安装光盘制作成本地软件源使用的,例如,Ubuntu、CentOS都可以将安装光盘制作成本地软件源。理论上,银河麒麟桌面版作为Ubuntu的衍生版,应该也可以这么做。但经测试银河麒麟桌面版安装盘中的Release文件被删除了(Release文件记录了文件的哈希值)。由于运行sudo apt update的时候会先校检Release文件的签名信息,如果不符合则认为是无效的仓库。银河麒麟桌面版安装光盘只内置了有限几种安装包,如图39所示。

图39  银河麒麟桌面版安装光盘可选deb包

这些deb包对应的就是在安装系统时可选的几款软件,如图310所示。

图310  银河麒麟桌面版安装时软件包选择界面

因此,银河麒麟桌面版不需要、也无法直接搭建光盘软件源。

APT的安全特性

APT使用GPG对软件包进行签名和验证,以确保包的完整性和来源的可信度,这一机制称为apt-secure。

1. apt-secure的工作机制

apt-secure是APT的一个安全特性,用于验证软件包的来源和完整性。它通过签名和验证机制,确保从仓库下载的包是可信的。

(1)包签名与验证过程。

  • 包签名:开发者使用私钥对软件包进行签名。
  • 发布:签名的包上传到软件仓库。
  • 下载:用户使用APT下载软件包。
  • 验证:APT使用仓库的公钥验证包的签名。

(2)Release文件和InRelease文件。

APT使用多个文件来管理软件包仓库和包的元数据,其中Release文件和InRelease文件是两个重要的文件。Release文件是包含仓库元数据的文件,描述了软件包仓库的各个部分包含的包以及这些包的元数据。它主要用于确保仓库的一致性和完整性。InRelease文件是Release文件的增强版本,它不仅包含Release文件中的所有内容,还包括一个内嵌的GPG签名。

2. 使用apt-key命令管理密钥

apt-key是一个用于管理APT的GPG密钥的命令行工具。它可以添加、删除和列出系统信任的密钥(如表38所示)。表3-8中的apt-key adv是apt-key的子命令,提供了与GPG交互的高级功能。

表38  apt-key命令使用示例

命    令

解    释

apt-key list

列出系统中所有已添加的APT密钥

apt-key add /path/to/keyfile.asc

wget -qO - https://example.com/repo-key.gpg | apt-key add -

从本地文件中导入密钥

从URL获取并添加GPG公钥

apt-key del <key-id>

删除指定的密钥

apt-key fingerprint <key-id>

显示指定密钥的指纹信息

apt-key update

更新所有密钥(已弃用)

apt-key adv --keyserver <keyserver> --recv-keys
<key-id>

apt-key adv --export <key-id> > exported-key.asc

从指定的密钥服务器下载并导入密钥

导出指定的密钥到文件

3. 密钥相关故障处置

(1)案例1。

在使用APT的过程中,特别是在添加PPA仓库(后文将详细讲解)时,经常会遇到如图311所示的错误。

图311  缺少公钥错误

该错误通常是由于PPA仓库的公钥未导入到系统中,导致APT无法验证软件包的签名而引起的。遇到此类故障,可以使用如下命令添加缺少的公钥:

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 8094BB14F4E3FBBE

命令中的hkp://keyserver.ubuntu.com:80为存储公钥的服务器(称之为keyserver),可用的keyserver包括如下这些。

keyserver.ubuntu.com

pgp.mit.edu

subkeys.pgp.net

www.gpg-keyserver.de

(2)案例2。

图3-12展示了使用在线脚本安装某软件时的报错信息,这是另一种缺少公钥错误的示例。

图312  GPG缺少公钥错误

这类错误处置步骤如下所述。

按照图3-12中提示,执行下面的命令获取缺失的公钥:

gpg2 --keyserver hkp://keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB

导出所有GPG公钥:

gpg --export --armor > all-gpg-keys.asc

将密钥文件复制到/etc/apt/trusted.gpg.d/:

sudo cp all-gpg-keys.asc /etc/apt/trusted.gpg.d/

通过这种方式,可以确保将GPG管理的所有密钥都导入APT的密钥环中。


http://www.mrgr.cn/news/95598.html

相关文章:

  • 【Linux】线程库
  • 重温Ubuntu 24.04 LTS
  • 麒麟Win32运行环境
  • PyTorch 面试题及参考答案(精选100道)
  • 图解AUTOSAR_DefaultErrorTracer
  • 本地部署Dify 添加Ollama模型DeepSeek
  • 大模型提示词工程师的自我修养-提示技巧二(思维树、RAG检索增强生成) -(专题2)
  • Guava:Google开源的Java工具库,太强大了
  • hive计算机
  • 使用VS2022编译CEF
  • 【数据结构】单链表
  • kotlin知识体系(四) : inline、noinline、crossinline 关键字对应编译后的代码是怎样的 ?
  • K8S学习之基础四十四:k8s中部署Kibana
  • 【拒绝算法PUA】LeetCode 2116. 判断一个括号字符串是否有效
  • UNIX网络编程笔记:客户/服务器程序示例
  • Jboss中间件漏洞攻略
  • 算法基础篇(1)(蓝桥杯常考点)
  • 题型笔记 | Apriori算法
  • MinGW与使用VScode写C语言适配
  • QEMU源码全解析 —— 块设备虚拟化(7)