浅谈网络 | 应用层之流媒体与P2P协议
目录
- 流媒体
- 名词系列
- 视频的本质
- 视频压缩
- 编码过程
- 如何在直播中看到帅哥美女?
- RTMP 协议
- P2P
- P2P 文件下载
- 种子文件 (.torrent)
- 去中心化网络(DHT)
- 哈希值与 DHT 网络
- DHT 网络是如何查找
流媒体
直播系统组成与协议
近几年直播比较火,很多人都喜欢看直播。那么一个直播系统里面都有哪些组成部分,都使用了什么协议呢?
无论是直播还是点播,其实都是对于视频数据的传输。一提到视频,大家都爱看,但一提到视频技术,大家都头疼,因为名词实在是太多了。
名词系列
- 名词系列一:AVI、MPEG、RMVB、MP4、MOV、FLV、WebM、WMV、ASF、MKV。例如 RMVB 和 MP4,看着是不是很熟悉?
- 名词系列二:H.261、H.262、H.263、H.264、H.265。这个是不是就没怎么听过了?别着急,要重点关注 H.264。
- 名词系列三:MPEG-1、MPEG-2、MPEG-4、MPEG-7。MPEG 好像听说过,但后面的数字是怎么回事?熟悉又陌生?
视频的本质
视频是什么?其实就是快速播放一连串连续的图片。每一张图片称为一帧。只要每秒钟帧的数据足够多,即播放得足够快,人的眼睛看不出这是一张张独立的图片,这就是我们常说的帧率(FPS)。
每一张图片,由像素组成,假设为 1024×768,每个像素由 RGB 组成,每个 8 位,共 24 位。
计算视频大小:
每秒钟的视频大小:
30帧 × 1024 × 768 × 24 = 566,231,040 Bits = 70,778,880 Bytes
一分钟视频大小:
4,246,732,800 Bytes = 4 GB
视频压缩
如何将如此大的数据量压缩呢?编码就是一个压缩的过程。
视频和图片的压缩特点
- 空间冗余:相邻像素之间有较强的相关性,可以通过算法计算出中间的像素。
- 时间冗余:视频序列中相邻图像内容相似,利用已有的图片进行预测和推断。
- 视觉冗余:人眼对某些细节不敏感,因此可以丢失一些数据。
- 编码冗余:像素值出现的概率不同,概率高的像素使用较少的字节,概率低的像素使用更多字节,类似霍夫曼编码。
视频编码的两大流派
- ITU-VCEG:侧重传输,主要制定了 H.261, H.264 等标准。
- ISO-MPEG:侧重存储,主要制定了 MPEG-1, MPEG-2 等标准。
后来的 H.264/MPEG-4 AVC 标准就是这两个组织合作制定的。
编码过程
视频流通过编码变成二进制,这些二进制数据会按照一定的格式保存为文件。这个文件格式就是名词系列一中的各类格式(如 MP4、RMVB 等)。
如何在直播中看到帅哥美女?
视频流可以通过网络协议封装并传输。在直播过程中,视频从主播端推送到服务器,服务器再转发到客户端。这是一个典型的推流与拉流过程。
编码过程细节
视频编码后,视频被分成三种帧类型:
- I帧(关键帧):完整的图片,可以单独解码。
- P帧(前向预测编码帧):与前一个关键帧或 P 帧的差异,解码时需要参考之前的图像。
- B帧(双向预测内插编码帧):记录与前后帧的差异,解码时需要前后帧的参考数据。
推流与拉流
- 推流:将编码后的视频数据通过 RTMP 协议传输到流媒体服务器。
- 拉流:观众通过 RTMP 协议从流媒体服务器拉取视频流并解码,最终显示在客户端。
RTMP 协议
RTMP 是基于 TCP 的协议,确保数据有序传输。推流和拉流过程中,RTMP 会将视频流分成多个 Chunk 进行传输,以适应低带宽环境。
观众的客户端通过 RTMP 推流的过程:
观众的客户端通过 RTMP 拉流的过程:
小结
- 视频编码通过时空冗余压缩数据;
- 编码后的视频流被分为 NALU 单元进行网络传输;
- 使用 RTMP 协议进行视频流的推送和拉取;
- 视频流在客户端进行解码,播放出最终的视频。
P2P
在下载电影时,我们通常会选择不同的下载方式。最常见的方式是通过 HTTP 协议进行下载,但是许多人可能有过这样的体验:当文件较大时,使用浏览器直接下载的速度极其缓慢。
另一种常见的下载方式是通过 FTP(文件传输协议)。FTP 采用两个 TCP 连接来传输文件,具体包括控制连接和数据连接。
-
控制连接:服务器通常通过端口 21 以被动的方式监听,客户端则主动发起连接。这条连接负责传递命令和服务器的响应。例如,常见的命令包括:
list
:列出文件目录;retr
:下载文件;store
:上传文件。
-
数据连接:每次文件传输时,客户端和服务器会建立一个独立的数据连接来传输文件内容。
FTP 工作模式
FTP 有两种工作模式,分别是主动模式(PORT)和被动模式(PASV)。这两种模式的区别在于数据连接的建立方式,下面分别介绍:
-
主动模式(PORT):在主动模式下,客户端会随机选择一个大于 1024 的端口 N,然后通过端口 21 向服务器发起连接。客户端会向服务器发出一个
PORT N+1
的命令,告诉服务器自己打开了一个监听端口 N+1。接着,服务器从自己的端口 20 主动连接到客户端的端口 N+1 来建立数据连接。 -
被动模式(PASV):在被动模式下,客户端首先通过端口 21 连接到服务器并发送
PASV
命令。随后,服务器会选择一个大于 1024 的端口 P,并返回227 entering passive mode
消息,告知客户端数据传输的端口号。客户端收到这个消息后,会使用端口 N+1 连接服务器的端口 P,并通过这两个端口进行数据传输。
P2P 文件下载
虽然 HTTP 和 FTP 是常见的文件下载方式,但它们都存在一个主要的缺点:单一服务器的带宽压力大。因为这两种方式采用的是传统的客户端-服务器架构,所有数据都依赖于中心服务器。
为了克服这一问题,P2P(Peer-to-Peer)文件传输方式应运而生。P2P 不再依赖单一的服务器来存储和传输资源,而是通过多台设备(即 Peer)之间的点对点连接来分散资源。
在 P2P 模式下,当你想下载一个文件时,系统会连接到已经拥有该文件的其他 Peer,你可以直接从这些设备下载数据,而无需依赖中心服务器。一旦下载完成,你的设备也会成为 P2P 网络的一部分,其他设备可以通过你的设备获取该文件。这样,随着网络中的 Peer 越多,下载速度也越快。
常见的 P2P 下载工具,如 BitTorrent,就利用这种分布式下载方式。在使用 BitTorrent 等软件时,你不仅会看到下载流量,还会看到上传流量。因为你在下载的同时,也在为其他用户提供文件。
种子文件 (.torrent)
在 P2P 下载中,如何知道哪些 Peer 已经拥有文件是一个关键问题。这个问题通过“种子”文件(.torrent)来解决。我们比较熟悉的 .torrent 文件由两部分组成:announce(tracker URL) 和 文件信息。
种子文件结构
- 文件信息(Info 区):包含文件的基本信息,如文件数量、每个文件的大小、目录结构等。
- Name 字段:指定顶层目录的名称。
- 每个段的大小:BT 协议将文件拆分成多个小段,这样可以并行下载各个段。
- 段哈希值:每个文件段的 SHA-1 哈希值,所有段的哈希值合并在一起,保证文件完整性。
下载过程
- 解析种子文件:BT 客户端首先解析 .torrent 文件,获取 tracker 地址,然后连接到 tracker 服务器。
- 连接和获取 Peer 信息:tracker 服务器回应请求,提供其他下载者的 IP 地址,包括发布者。客户端通过这些信息连接到其他下载者。
- 交换文件段:客户端和其他 Peer 之间交换文件段。每个客户端会告知对方自己已下载的段,未下载的部分会从其他 Peer 处获取。
- 文件完整性验证:每次下载一个文件段后,客户端会计算该段的哈希值并与 .torrent 文件中的值对比。如果匹配,说明该段下载正确,否则需要重新下载。
依赖 Tracker 的问题
这种下载方式依赖于 tracker 服务器,tracker 是一个中心化的服务器,负责登记哪些用户请求哪些文件并协调 Peer 之间的连接。尽管下载过程是去中心化的,但加入 P2P 网络时仍需要借助 tracker 来进行连接。
缺点:如果 tracker 服务器出现故障或被屏蔽,P2P 下载就会受到影响,导致无法正常工作。
去中心化网络(DHT)
能否实现完全的去中心化?答案是可以的,这就是 DHT(Distributed Hash Table) 的应用。
什么是 DHT?
DHT 是一种分布式哈希表,每个加入 DHT 网络的节点都负责存储网络中的资源信息和其他成员的联系信息。简单来说,所有节点共同构成一个庞大的分布式数据库,分担信息存储和查询的工作。
Kademlia 协议
DHT 网络的一个著名协议是 Kademlia 协议,类似于区块链的概念,但更为抽象。下面我们来详细讲解它的工作原理。
DHT 网络中的角色
每个启动的 BitTorrent 节点扮演两个角色:
- Peer:监听一个 TCP 端口,用于上传和下载文件。这个角色标识该节点拥有某个文件。
- DHT Node:监听一个 UDP 端口,加入 DHT 网络。在 DHT 网络中,每个节点都有一个唯一的 ID,它是一个长串的哈希值。
文件索引与责任
在 DHT 网络中,每个节点并不存储所有文件,而是负责存储文件索引信息。具体来说:
- 每个 DHT 节点需要知道某些文件在哪些节点上保存,但它自己不一定存储这些文件。
- 这些节点通过 DHT 网络相互联系,共同维护文件的索引信息,确保文件的分布是去中心化的。
哈希值与 DHT 网络
每个 DHT node 并不拥有全局的文件信息,它只需要知道一部分文件的信息。要确定一个节点需要知道哪些文件,哈希算法便应运而生。
哈希值与文件
每个文件通过哈希算法计算出一个哈希值,而每个 DHT node 的 ID 长度与哈希值相同。
DHT 网络的规则是:如果某个文件的哈希值与某个 DHT node 的 ID 完全相同,那么该节点负责知道这个文件的下载位置。尽管该节点可能没有存储文件本身。
节点 ID 与文件哈希相似性
实际上,完全匹配的 DHT node 很难找到。为了应对这一问题,DHT 网络规定了:除了与哈希值完全相同的节点,还允许 与哈希值接近的 N 个节点 知道该文件的信息。
那么,如何判断“接近”呢?简单来说,接近是指哈希值在某些位上的差异较小。例如,修改文件哈希值的最后几位,仍然算作“接近”。
文件与节点的匹配过程
举个例子:
- 文件 1 的哈希值与 node C 的 ID 完全匹配。因此,node C 知道文件 1 的下载位置,尽管它本身并没有存储文件 1。
- 文件 2 的哈希值与 node E 的 ID 完全匹配,但 node D 的 ID 与 E 的哈希值很接近,因此 node D 也能得知文件 2 的位置。
新节点加入 DHT 网络
当一个新的节点 node new 加入 DHT 网络并想下载文件 1 时,首先它会找到种子文件(.torrent)中的 DHT 节点列表,并通过其中任意一个节点加入网络。
node new 会计算文件 1 的哈希值,并查找与哈希值匹配或接近的节点,如 node C。如果 node new 不能直接联系到 node C,它会向它能够联系到的其他节点询问,直到找到连接 node C 或其他相似节点的路径。
一旦 node new 开始下载文件,它就会向网络中其他节点报告自己也拥有该文件,成为新的文件“源”。
去中心化与分布式共享
此时,DHT 网络已经实现了文件的分布式共享。每个节点既能存储文件信息,又能提供文件下载路径,整个网络去除了中心化的依赖,保证了文件传输的高效性和可靠性。
DHT 网络的工作原理
-
节点 ID 与文件哈希:节点 ID 和文件哈希值都使用 160 位(20 字节)长度的哈希空间。
-
相似度计算:DHT 网络中节点 ID 的相似度通过 异或(XOR)运算 来判断。例如,对于 5 位 ID:
01010
和01000
的距离是00010
,即 2。01010
和00010
的距离是01000
,即 8。01010
和00011
的距离是01001
,即 9。
通过这种计算方式,判断 ID 之间的“距离”有助于确定哪些节点对文件的存储和下载路径最为重要。
类比社交网络
在 DHT 网络中,节点的距离更像是社交网络中的“社交距离”——即不同节点之间的联系程度,而非地理距离。就像在 LinkedIn 上,工作经历丰富的人可能与你的“社交距离”较近,尽管你们没有住在同一地方。
DHT 网络是如何查找
DHT(分布式哈希表)网络的查找和更新机制是通过 Kademlia 协议实现的,允许节点高效地查找其他节点和文件。以下是该协议的工作原理和核心机制:
1. 节点查找
假设节点 A 的 ID 为 00110
,需要查找节点 B,ID 为 10000
。这两个节点的异或距离为 10110
,即 A
和 B
之间的距离是 31。根据 Kademlia 协议,节点 A 会尝试在自己的 k-bucket 中查找 B,并根据以下步骤进行折半查找:
1.1 查找目标节点所在的 k-bucket
- A 计算异或值
10110
,并根据异或的结果确定 B 可能在的k-bucket
。在此例中,B 与 A 的 ID 从第 5 位开始不同,因此 B 可能在k-bucket 5
中。 - 如果 A 的
k-bucket 5
中存在 B,查找成功;如果不存在,继续下一步。
1.2 查找接近的节点
- 如果 A 没有在自己的
k-bucket 5
中找到 B,它会从该桶中随机选择一个节点 C,并请求 C 查询自己的通讯录,看看是否能找到 B。 - 由于 C 和 B 的 ID 在第 5 位相同,因此 C 能找到与 B 更接近的节点,进一步缩小查找范围。
- 这种过程逐步缩小距离,每次通过折半查找来加速查找过程。
1.3 查找过程的递归
- 如果 C 也没有找到 B,它会继续向自己的通讯录请求,直到找到距离 B 更近的节点,如 D,然后 D 继续查找,直到最终找到 B。
- 最坏的情况是,每次找到的节点都离目标节点较远,需要多个步骤才能最终找到 B。
1.4 查找效率
- Kademlia 协议采用了 折半查找 的机制,最多只需要
log2(N)
次查询(其中 N 为网络中节点总数)就能找到目标节点。这保证了查询过程的高效性。
2. 节点通信
在 DHT 网络中,节点之间通过 4 个核心指令进行通信:
- PING:测试一个节点是否在线,类似打电话确认对方是否还活跃。
- STORE:请求一个节点保存一份数据。加入网络的节点需要保存一定的数据。
- FIND_NODE:根据目标节点的 ID 查找该节点。即通过节点的 ID 查找节点的位置。
- FIND_VALUE:根据文件的哈希值(即 KEY)查找存储该文件的节点。实际上,这个操作与 FIND_NODE 类似,只不过目标是文件而非节点。
3. 节点的通讯录更新
Kademlia 协议通过更新每个节点的通讯录来保证网络的稳定性和高效性。每个节点的 k-bucket(即通讯录)按照接触时间倒序排列,最近联系的节点排在最前面。
3.1 更新机制
- 每次节点与其他节点接触时,都会检查这个节点是否已经在自己的 k-bucket 中。如果节点已经存在,它会被移到 k-bucket 列表的末尾,表示最近联系过的节点。
- 如果通讯录满了(通常是一个固定的大小,如 20 个节点),新的节点会替换最旧的节点。如果最旧的节点在线(通过 PING 测试),它会被移到通讯录的末尾;如果下线,则删除并加入新的节点。
3.2 维持网络稳定性
- 通过这种方式,Kademlia 协议保证了即使某些节点加入或离开网络,整体的网络结构和效率不会受到影响。节点始终保持高效且动态的通讯录,不断更新与其他节点的联系。
总结一下:
-
集中式下载 vs 非中心化下载:下载一个文件通常使用 HTTP 或 FTP,这两种方式都是依赖中心化服务器的,而 P2P(点对点)则采用了去中心化的方式,改变了传统的下载模式。
-
P2P 的两种方式:
- 基于 Tracker 的 P2P:这种方式中,元数据(即文件的位置信息)集中存储在 Tracker 上,而文件数据则分散存储在多个节点中。下载过程需要通过 Tracker 来获得文件的相关信息。
- 基于 DHT 的 P2P:这是一种完全去中心化的方式,文件的元数据和文件数据都被分散存储在整个网络中。每个节点都可能既是数据存储者,也可能是数据查找者,通过分布式哈希算法(DHT)来完成文件的查找和下载。
通过这两种方式,P2P 网络能够有效实现文件的共享和分发,并且避免了传统集中式下载的单点故障问题。
相关文章:

浅谈网络 | 应用层之流媒体与P2P协议
目录 流媒体名词系列视频的本质视频压缩编码过程如何在直播中看到帅哥美女?RTMP 协议 P2PP2P 文件下载种子文件 (.torrent)去中心化网络(DHT)哈希值与 DHT 网络DHT 网络是如何查找 流媒体 直播系统组成与协议 近几年直播比较火,…...

css vue vxe-text-ellipsis table 实现多行文本超出隐藏省略
分享 vxe-text-ellipsis table grid 多行文本溢出省略的用法 正常情况下如果需要使用文本超出隐藏,通过 css 就可以完成 overflow: hidden; text-overflow: ellipsis; white-space: nowrap;但是如果需要实现多行文本溢出,就很难实现里,谷歌…...

基于hexo框架的博客搭建流程
这篇博文讲一讲hexo博客的搭建及文章管理,也算是我对于暑假的一个交代 !!!注意:下面的操作是基于你已经安装了node.js和git的前提下进行的,并且拥有github账号 创建一个blog目录 在磁盘任意位置创建一个…...

数据结构-简单排序
一.前提 二.冒泡排序 三.插入排序 #include<iostream> using namespace std; typedef int ElemengType; void Bubble_Sort(ElemengType A[], int N) {for (int p N - 1; p > 0; p--) {int flag 0;for (int i 0; i < p; i) {if (A[i] > A[i 1]) {swap(A[i], …...
三十一:HTTP多种重定向跳转方式的差异
在现代网站开发中,HTTP 重定向是一种常见的技术,用于将用户的请求从一个 URL 跳转到另一个 URL。重定向机制广泛应用于网站迁移、SEO 优化、以及内容管理系统中。不同的 HTTP 状态码代表不同的重定向方式,每种方式的行为和适用场景各有不同。…...

利用Python爬虫精准获取淘宝商品详情的深度解析
在数字化时代,数据的价值日益凸显,尤其是在电子商务领域。淘宝作为中国最大的电商平台之一,拥有海量的商品数据,对于研究市场趋势、分析消费者行为等具有重要意义。本文将详细介绍如何使用Python编写爬虫程序,精准获取…...
架构师的英文:Architect
中文版 软件架构师 的英文是 “Software Architect”。 Software: 软件Architect: 架构师,通常指的是设计和规划某种系统或结构的人。 Software Architect 通常负责软件系统的整体设计、技术选型、架构规划,确保系统的可扩展性、可维护性和高效性等。…...

数据结构 ——— 计数排序算法的实现
目录 计数排序算法的思想 计数排序算法的实现 计数排序算法的思想 遍历数组,找出数组中的最大值 max 和 最小值 min 最大值 max 减去最小值 min 再加 1 得出数组元素的范围 range 利用 range 的大小 malloc 一个 count 数组用来计数 再对 count 数组进行初始化…...

k8s搭建Istio环境,案例pod一直处在Init:CrashLoopBackOff
1 部署calico网络环境,网上去找k8s版本对应的calico的配置文件,k8s2.8.0我用的3.28 2 安装istio环境 curl -L https://istio.io/downloadIstio | sh - # 省略istioctl生效的步骤 source <(istioctl completion zsh) istioctl install --set profile…...

Jenkins升级到最新版本后无法启动
1. 场景还原 最近在web界面将jenkins升级到最新版本后,后台无法启动jenkins服务,服务状态如下: 运行jenkins命令提示invalid Java version jenkins --version jenkins: invalid Java version: java version "1.8.0_202" Java(TM)…...

用户界面创建一个新的运动类型
● 现在我们需要根据我们之前规划的架构步骤来实现在用户界面创建一个运动类型 ● 首先我们在要获取用户在表单中输入的数据 //从表单中获取数据const type inputType.value;const distance inputDistance.value;const duration inputDuration.value;● 然后针对与不同的运动…...
ubuntu防火墙入门(一)——设置服务、关闭端口
本机想通过git clone gitgithub.com:skumra/robotic-grasping.git下载代码,firewall-config中需要为当前区域的防火墙开启SSH服务吗 是的,如果你想通过 git clone gitgithub.com:skumra/robotic-grasping.git 使用 SSH 协议从 GitHub 下载代码࿰…...
分治算法——二分查找(c++)(详解)
大家好,今天进入一个实用算法:分治算法。 1.分治算法介绍 分治算法,大概就是将一个大问题拆解成若干个小问题,将小问题一一解决,大问题也就迎刃而解。它包含了多种算法,比如递归、递推等。这里就讲解一下其…...

Binder架构
一、架构 如上图,binder 分为用户层和驱动层两部分,用户层有客户端(Client)、服务端(Server)、服务管理(ServiceManager)。 从用户空间的角度,使用步骤如下(…...
大数据治理:解锁数据价值,引领未来创新
目录 引言 一、大数据治理的定义 二、大数据治理的重要性 三、大数据治理的核心组件 四、大数据治理的实践案例 1. 数据标准化 2. 数据质量管理 案例一:医疗行业的大数据治理——智能医疗助手守护健康 引言 在数字化时代,数据已成为企业最宝贵的…...

解决windows下php8.x及以上版本,在Apache2.4中无法加载CURL扩展的问题
本文已首发于:秋码记录 若你也想搭建一个个人博客,可参考:国内 gitee.com Pages 下线了,致使众多站长纷纷改用 github、gitlab Pages 托管平台 在日新月异的信息化下,软件也在跟随着互联网的脚步,逐步推进…...

【韩顺平老师Java反射笔记】
反射 文章目录 基本使用反射机制java程序在计算机有三个阶段反射相关的主要类 反射调用优化Class类的常用方法获取Class对象的6种方式哪些类型有Class对象类加载类加载时机类加载过程图 通过反射获取类的结构信息第一组:java.lang.Class类第二组:java.la…...

Arrays.asList()新增报错,该怎么解决
一、前言 在 Java 开发中,Arrays.asList() 是一个常用的工具方法,它允许开发者快速将数组转换为列表。尽管这个方法非常方便,但许多开发者在使用时可能会遭遇一个常见的错误:尝试向由 Arrays.asList() 返回的列表中添加元素时抛出…...

【热门主题】000072 分布式数据库:开启数据管理新纪元
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 【热…...

基于Springboot开发的云野旅游平台
一、功能介绍 云野旅游平台包含管理员、用户两个角色以及前后台系统。 前台系统功能 用户登录成功后,可以进行查看旅游路线、最新线路、旅游资讯、个人中心、后台管理、购物车、客服等功能模块。进行相对应操作。 后台系统功能 管理员或用户登录成功后…...

【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...