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

价格预言机的使用总结(一):Chainlink篇

文章首发于公众号:Keegan小钢


前言

价格预言机已经成为了 DeFi 中不可获取的基础设施,很多 DeFi 应用都需要从价格预言机来获取稳定可信的价格数据,包括借贷协议 Compound、AAVE、Liquity ,也包括衍生品交易所 dYdX、PERP 等等。

目前最主流的价格预言机主要有 Chainlink、UniswapV2、UniswapV3 ,这几种价格预言机的接入方式和适用场景都不太一样,可以单独使用,也可以结合使用。鉴于不少同学还不知道这些预言机具体有哪些接入方式,也不了解背后的机制,更不清楚如何才能做到保证安全性的同时又能以最小的成本接入。下面,我将分享下我的经验总结,以供参考。

Chainlink

先从 Chainlink 的价格预言机开始聊起,这应该是使用最广泛的价格预言机了。

其实,Chainlink 提供的产品不只是价格预言机,还有其他产品,包括 Verifiable Random Numbers (VRF)、Call External APIs、Chainlink Keepers 。当然,使用最广泛的还是价格预言机,叫 Data Feeds

Chainlink Data Feeds 目前已经支持了多条链,主要还是 EVM 链,包括 Ethereum、BSC、Heco、Avalanche 等,也包括 Arbitrum、Optimism、Polygon 等 L2 的链。另外,也支持了非 EVM 链,目前支持了 SolanaTerra 。不过,我对非 EVM 链并不熟悉,所以只讲 EVM 链的使用。

DeFi 应用接入使用 Chainlink Data Feeds 其实很简单,而且还有不同的使用方式,下面就来看看最常用的使用方式。

Price Feed

第一种使用方式,官方给的示例代码是这样的:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";contract PriceConsumerV3 {AggregatorV3Interface internal priceFeed;/*** Network: Kovan* Aggregator: ETH/USD* Address: 0x9326BFA02ADD2366b30bacB125260Af641031331*/constructor() {priceFeed = AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331);}/*** Returns the latest price*/function getLatestPrice() public view returns (int) {(uint80 roundID, int price,uint startedAt,uint timeStamp,uint80 answeredInRound) = priceFeed.latestRoundData();return price;}
}

首先,每个交易对都有一个单独的 Price Feed ,也叫 Aggregator ,其实就是一个个 AggregatorProxy ,像下面这样:

1.png

可以看到,每个 Pair 都有一个对应的 Proxy,读取价格其实就是从 Proxy 提供的方法读取的。Proxy 的具体实现稍微有点复杂,但 DeFi 应用要接入的话,只要知道 Interface 就够了,这个 Interface 则很简单,就是示例代码中所引入的 AggregatorV3Interface,其代码如下:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;interface AggregatorV3Interface {function decimals() external view returns (uint8);function description() external view returns (string memory);function version() external view returns (uint256);// getRoundData and latestRoundData should both raise "No data present"// if they do not have data to report, instead of returning unset values// which could be misinterpreted as actual reported values.function getRoundData(uint80 _roundId)externalviewreturns (uint80 roundId,int256 answer,uint256 startedAt,uint256 updatedAt,uint80 answeredInRound);function latestRoundData()externalviewreturns (uint80 roundId,int256 answer,uint256 startedAt,uint256 updatedAt,uint80 answeredInRound);
}

就 5 个查询方法而已,简单介绍下这几个方法:

  • decimals() :返回的价格数据的精度位数,一般为 8 或 18
  • description() :一般为交易对名称,比如 ETH / USD
  • version() :主要用来标识 Proxy 所指向的 Aggregator 类型
  • getRoundData(_roundId) :根据 round ID 获取当时的价格数据
  • latestRoundData() :获取最新的价格数据

大部分应用场景可能只需要读取最新价格,即调用最后一个方法,其返回参数中,answer 就是最新价格。

另外,大部分应用读取 token 的价格都是统一以 USD 为计价单位的,若如此,你会发现,以 USD 为计价单位的 Pair,精度位数都是统一为 8 位的,所以一般情况下也无需根据不同 token 处理不同精度的问题。

当然,在实际应用中,肯定不会只读取一个固定 Token 的价格,更多场景是根据 Token 读取该 Token 的 USD 价格,因此可以将前面的示例合约升级为如下:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "@openzeppelin/contracts/access/Ownable.sol";contract PriceConsumerV3 is Ownable {mapping(address => AggregatorV3Interface) internal priceFeedMap;function setPriceFeed(address token, address priceFeed) external onlyOwner {priceFeedMap[token] = AggregatorV3Interface(priceFeed);}/*** Returns the latest price*/function getLatestPrice(address token) public view returns (int) {(uint80 roundID, int price,uint startedAt,uint timeStamp,uint80 answeredInRound) = priceFeedMap[token].latestRoundData();return price;}
}

原先的示例只能读取 ETH/USD 一个 Pair 的价格,而现在则可以设置和读取多个不同 token 的价格。比如,现在想要读取 UNI 的 USD 价格,就可以先查出 UNI/USD 的 priceFeed,查出其 Proxy 为 0x553303d460EE0afB37EdFf9bE42922D8FF63220e ,而 UNI token 地址为 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984,那就可以调用:

setPriceFeed("0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984", "0x553303d460EE0afB37EdFf9bE42922D8FF63220e");

如此,UNI 所使用的 priceFeed 就设置好了,想读取 UNI 的最新价格时,调用 getLatestPrice() 就可读取到结果了,如下:

int price = getLatestPrice("0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984");

另外,mapping 所使用的 key 也可以不用 token address,改用 token symbol 或其它具有唯一标识性的属性也是可以的。

虽然该示例比较简单,很多实际应用中,可能比这复杂,但基本核心功能是差不多的了。

Feed Registry

第一种接入方式虽然已经很简单,但每个 token 都需要 owner 执行 setPriceFeed ,治理成本其实有点高,对某些场景来说就不太灵活。这时候,就可以考虑使用第二种方式来接入 Chainlink Data Feeds 了,通过使用 Feed Registry 的方式来接入。

Feed Registry 可以简单理解为 PriceFeeds 的聚合器,已经聚合了多个 priceFeed,有了它,使用者就无需自己去设置 priceFeed 了,可直接通过 Feed Registry 读取价格数据,如下图:

2.png

官方给的使用示例代码则如下:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;import "@chainlink/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol";
import "@chainlink/contracts/src/v0.8/Denominations.sol";contract PriceConsumer {FeedRegistryInterface internal registry;/*** Network: Ethereum Kovan* Feed Registry: 0xAa7F6f7f507457a1EE157fE97F6c7DB2BEec5cD0*/constructor(address _registry) {registry = FeedRegistryInterface(_registry);}/*** Returns the ETH / USD price*/function getEthUsdPrice() public view returns (int) {(uint80 roundID,int price,uint startedAt,uint timeStamp,uint80 answeredInRound) = registry.latestRoundData(Denominations.ETH, Denominations.USD);return price;}/*** Returns the latest price*/function getPrice(address base, address quote) public view returns (int) {(uint80 roundID, int price,uint startedAt,uint timeStamp,uint80 answeredInRound) = registry.latestRoundData(base, quote);return price;}
}

可看到,开头引入了两个 sol 文件,FeedRegistryInterface 和 Denominations。Denominations 是一个很简单的 library,主要定义了各种货币的地址,如下:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;library Denominations {address public constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;address public constant BTC = 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB;// Fiat currencies follow https://en.wikipedia.org/wiki/ISO_4217address public constant USD = address(840);address public constant GBP = address(826);address public constant EUR = address(978);// ... other fiat currencies
}

FeedRegistryInterface 则定义了不少函数,包括和 AggregatorV3Interface 一样的几个函数,只是每个函数相比 AggregatorV3Interface 多了两个参数:basequote如下:

interface FeedRegistryInterface {// V3 AggregatorV3Interfacefunction decimals(address base, address quote) external view returns (uint8);function description(address base, address quote) external view returns (string memory);function version(address base, address quote) external view returns (uint256);function latestRoundData(address base, address quote)externalviewreturns (uint80 roundId,int256 answer,uint256 startedAt,uint256 updatedAt,uint80 answeredInRound);function getRoundData(address base, address quote, uint80 _roundId)externalviewreturns (uint80 roundId,int256 answer,uint256 startedAt,uint256 updatedAt,uint80 answeredInRound);// ... other functions
}

假设交易对为 UNI/USD,那 base 为 UNI 的 token 地址,quote 则为 USD 的地址,即为 Denominations.USD;假设交易对为 ETH/BTC,那 base 则为 Denominations.ETH,quote 为 Denominations.BTC。

另外,也可以通过 getFeed(address base, address quote) 直接读取到 priceFeed。

可以发现,使用 Feed Registry 的方式,主要都是用 base/quote 的方式进行查询。

FeedRegistry 里的每个 priceFeed 则是通过先后调用 proposeFeed()confirmFeed() 两个函数设置的,不过这两个函数只有 FeedRegistry 的 owner 才可以调用。

喂价机制

至此,我们已经知道如何接入 Chainlink Data Feeds 来获取价格信息了,但还不够,我们还要了解背后的喂价机制,也要了解价格数据多久更新一次的,如此才能更好地判定 Chainlink 的价格预言机是否能满足具体的场景需求。

首先,Price Feed 的价格是通过多个层级的数据聚合得到的。实际上有三个数据聚合层:数据源聚合、节点运营商聚合、预言机网络聚合

3.png

最原始的价格数据主要来源于币安、火币、Coinbase 等中心化交易平台,以及 Uniswap、Sushi 等去中心化交易平台。存在一些专门做数据聚合的服务商(比如 amberdata、CoinGecko ),会从这些交易平台收集原始的价格数据,并对这些数据源进行加工整合,比如根据交易量、流动性和时差等进行加权计算。

这就是第一个层面的聚合,对数据源的聚合 。拥有可靠的价格数据源的关键是要有全面的市场覆盖,才能保证一个价格点能代表所有交易环境的精确聚合,而不是单个交易所或少数交易所的价格,以防止数据被人为操纵和出现价格偏差。也因此,为了确保数据具有高度的防篡改和可靠性,Chainlink Data Feeds 只会从优质的数据聚合服务商获取数据,这意味着每个数据源都代表一个从所有中心化和去中心化交易所聚合的经过交易量调整的精细价格点,也因此可以有效抵抗闪电贷或价格异常偏差等攻击。

第二层则是 Chainlink Node Operators 所做的聚合。每个 Chainlink Node Operator 主要负责运行用于在区块链上获取和广播外部市场数据的 Chainlink 核心软件。Node Operators 会从多个独立的数据聚合服务商获取价格数据,并获取它们之间的中值,剔除掉异常值和 API 停机时间。比如,从 A 数据聚合服务商获取到价格点为 7.0,从 B 服务商获取到价格点为 7.2,那取中值后的价格点为 7.1。这意味着不仅每个单独的数据源反映了来自所有交易环境的聚合价格点,而且每个单独的节点的响应代表了来自多个数据源的聚合,进一步防止任何单一来源成为故障点,即避免了单点故障。

最后一层则是整个预言机网络的聚合,其聚合的方式有多种,但最常见的聚合方式是当响应节点数量达到预设值时对数据取中值。比如总共有 31 个节点,预设值为 21,即收到了 21 个节点的响应后,就取这些节点的价格数据的中值作为最终的价格。不过,并非每一轮的价格结果都会更新到链上,只有满足两个触发参数之一的时候才会更新:偏差阈值(Deviation Threshold)和心跳阈值(Heartbeat Threshold) 。而且,不同 PriceFeed 的这两个参数的值可能会不一样。

4.png

比如,ETH/USD 的偏差阈值为 0.5%,即表示新一轮的价格点跟上一次更新的价格偏差超过 0.5% 的时候才会更新链上价格;而心跳阈值为 3600 秒,即表示上一次价格更新后过了 1 小时后才会更新链上价格。另外,因为每一轮的数据聚合都不是实时的,也需要时间,再加上偏差阈值的限制,所以,有时候,要隔几十分钟才会有价格更新,这点比较关键,需要清楚。有些 Price Feed 的偏差阈值比较大,会高达十几个小时才会有价格更新,比如下面这个:

5.png

可看到,其偏差阈值高达 5%,且已经长达 11 个小时没有价格更新了,而它的心跳阈值其实也比较高,长达 24 小时。

高达 5% 的偏差阈值,且这么长时间都没有更新价格,这如果是应用到一些高杠杆的交易产品,可能就不太合适了。

总结

总而言之,Chainlink 价格预言机接入方便,且安全性还是比较高的,但因为其价格更新机制存在偏差阈值,导致价格更新比较慢,短则几分钟或几十分钟更新一次,长则可能达 24 小时才更新一次,因此,一般只适用于对价格更新不太敏感的应用。这也是 Chainlink 价格预言机的局限性,并无法适用所有场景的应用。

相关文章:

价格预言机的使用总结(一):Chainlink篇

文章首发于公众号:Keegan小钢 前言 价格预言机已经成为了 DeFi 中不可获取的基础设施,很多 DeFi 应用都需要从价格预言机来获取稳定可信的价格数据,包括借贷协议 Compound、AAVE、Liquity ,也包括衍生品交易所 dYdX、PERP 等等。…...

【Pyhton】读取寄存器数据到MySQL数据库

目录 步骤 modsim32软件配置 Navicat for MySQL 代码实现 步骤 安装必要的库:确保安装了pymodbus和pymysql。 配置Modbus连接:设置Modbus从站的IP地址、端口(对于TCP)或串行通信参数(对于RTU)。 连接M…...

jmeter-beanshell学习3-beanshell获取请求报文和响应报文

前后两个报文,后面报文要用前面报文的响应结果,这个简单,正则表达式或者json提取器,都能实现。但是如果后面报文要用前面请求报文的内容,感觉有点难。最早时候把随机数写在自定义变量,前后两个接口都用这个…...

【C++】B树及其实现

写目录 一、B树的基本概念1.引入2.B树的概念 二、B树的实现1.B树的定义2.B树的查找3.B树的插入操作4.B树的删除5.B树的遍历6.B树的高度7.整体代码 三、B树和B*树1.B树2.B*树3.总结 一、B树的基本概念 1.引入 我们已经学习过二叉排序树、AVL树和红黑树三种树形查找结构&#x…...

C++(Qt)-GIS开发-QGraphicsView显示瓦片地图简单示例

C(Qt)-GIS开发-QGraphicsView显示瓦片地图简单示例 文章目录 C(Qt)-GIS开发-QGraphicsView显示瓦片地图简单示例1、概述2、实现效果3、主要代码4、源码地址 更多精彩内容👉个人内容分类汇总 👈👉GIS开发 👈 1、概述 支持多线程加…...

CTFShow的RE题(三)

数学不及格 strtol 函数 long strtol(char str, char **endptr, int base); 将字符串转换为长整型 就是解这个方程组了 主要就是 v4, v9的关系, 3v9-(v10v11v12)62d10d4673 v4 v12 v11 v10 0x13A31412F8C 得到 3*v9v419D024E75FF(1773860189695) 重点&…...

WordPress主题开发进群付费主题v1.1.2 多种引流方式

全新前端UI界面,多种前端交互特效让页面不再单调,进群页面群成员数,群成员头像名称,每次刷新页面随机更新不重复,最下面评论和点赞也是如此随机刷新不重复 进群页面简介,群聊名称,群内展示&…...

SAP中的 UPDATA TASK 和 BACKGROUND TASK

前言: 记录这篇文章起因是调查生产订单报工问题引申出来的一个问题,后来再次调查后了解了其中缘由,大概记录以下,如有不对,欢迎指正。问题原贴如下: SAP CO11N BAPI_PRODORDCONF_CREATE_TT连续报工异步更…...

UDP协议:独特之处及其在网络通信中的应用

在网络通信领域,UDP(用户数据报协议,User Datagram Protocol)是一种广泛使用的传输层协议。与TCP(传输控制协议,Transmission Control Protocol)相比,UDP具有其独特的特点和适用场景…...

支持向量机(Support Vector Machine,SVM)及Python和MATLAB实现

支持向量机(Support Vector Machine,SVM)是一种经典的机器学习算法,广泛应用于模式识别、数据分类和回归分析等领域。SVM的背景可以追溯到1990s年代,由Vladimir Vapnik等人提出,并在之后不断发展和完善。 …...

【RT-thread studio 下使用STM32F103-学习sem-信号量-初步使用-线程之间控制-基础样例】

【RT-thread studio 下使用STM32F103-学习sem-信号量-初步使用-线程之间控制-基础样例】 1、前言2、环境3、事项了解(1)了解sem概念-了解官网消息(2)根据自己理解,设计几个使用方式(3)不建议运行…...

使用nodejs输出著作权申请所需的word版源码

使用nodejs输出著作权申请所需的word版源码 背景 软件著作权申请需要提供一份80页的word版源代码,如果手工复制源码到word文档中,工作量将无聊到让任何一个DAO人员血压爆表,因此我们不得不编写一个简单的文本处理代码,通过自动方…...

[Vite]vite-plugin-react和vite-plugin-react-swc插件原理了解

[Vite]vite-plugin-react和vite-plugin-react-swc插件原理了解 共同的作用 JSX 支持:插件为 React 应用程序中的 JSX 语法提供支持,确保它可以被正确地转换为 JavaScript。Fast Refresh:提供热更新功能,当应用程序在开发服务器上…...

记一次使用“try-with-resources“的语法导致的BUG

背景描述 最近使用try-catch的时候遇到了一个问题,背景是这样的:当第一次与数据库建立连接以后执行查询完毕并没有手动关闭连接,但是当我第二次获取连接的时候报错了,显示数据库连接失败,连接已经关闭。 org.postgres…...

用Excel处理数据图像,出现交叉怎么办?

一、问题描述 用excel制作X-Y散点图,意外的出现了4个交叉点,而实际上的图表数据是没有交叉的。 二、模拟图表 模拟部分数据,并创建X-Y散点图,数据区域,X轴数据是依次增加的,因此散点图应该是没有交叉的。…...

SpringBoot | 大新闻项目后端(redis优化登录)

该项目的前篇内容的使用jwt令牌实现登录认证,使用Md5加密实现注册,在上一篇:http://t.csdnimg.cn/vn3rB 该篇主要内容:redis优化登录和ThreadLocal提供线程局部变量,以及该大新闻项目的主要代码。 redis优化登录 其实…...

ESP32——物联网小项目汇总

商品级ESP32智能手表 [文章链接] 用ESP32,做了个siri?!开源了! [文章链接]...

flutter:监听路由的变化

问题 当从路由B页面返回路由A页面后&#xff0c;A页面需要进行数据刷新。因此需要监听路由变化 解决 使用RouteObserver进行录音监听 创建全局变量&#xff0c;不在任何类中 final RouteObserver<PageRoute> routeObserver RouteObserver<PageRoute>();在mai…...

Linux多进程和多线程(六)进程间通信-共享内存

多进程(六) 共享内存共享内存的创建 示例: 共享内存删除 共享内存映射 共享内存映射的创建解除共享内存映射示例:写入和读取共享内存中的数据 写入: ### 读取: 大致操作流程: 多进程(六) 共享内存 共享内存是将分配的物理空间直接映射到进程的⽤户虚拟地址空间中, 减少数据在…...

ruoyi后台修改

一、日志文件过大分包 \ruoyi-admin\src\main\resources\logback.xml <!-- 系统日志输出 --> <appender name"file_info" class"ch.qos.logback.core.rolling.RollingFileAppender"><file>${log.path}/sys-info.log</file><!…...

macOS查看系统日志的方法

1、command空格键打开搜索框&#xff0c;输入‘控制台’并打开 2、选择日志报告&#xff0c;根据日期打开自己需要的文件就可以...

数字信号处理及MATLAB仿真(3)——采样与量化

今天写主要来编的程序就是咱们AD变换的两个步骤。一个是采样&#xff0c;还有一个是量化。大家可以先看看&#xff0c;这一过程当中的信号是如何变化的。信号的变换图如下。 先说说采样&#xff0c;采样是将连续时间信号转换为离散时间信号的过程。在采样过程中&#xff0c;连续…...

云端AI大模型群体智慧后台架构思考

1 大模型的调研 1.1 主流的大模型 openai-chatgpt 阿里巴巴-通义千问 一个专门响应人类指令的大模型。我是效率助手&#xff0c;也是点子生成机&#xff0c;我服务于人类&#xff0c;致力于让生活更美好。 百度-文心一言&#xff08;千帆大模型&#xff09; 文心一言"…...

算法系列--分治排序|再谈快速排序|快速排序的优化|快速选择算法

前言:本文就前期学习快速排序算法的一些疑惑点进行详细解答,并且给出基础快速排序算法的优化版本 一.再谈快速排序 快速排序算法的核心是分治思想,分治策略分为以下三步: 分解:将原问题分解为若干相似,规模较小的子问题解决:如果子问题规模较小,直接解决;否则递归解决子问题合…...

强化学习编程实战-1-一个及其简单的强化学习实例(多臂赌博机)

1.1 多臂赌博机 一台拥有K个臂的机器&#xff0c;玩家每次可以摇动K个臂中的一个&#xff0c;摇动后&#xff0c;会吐出数量不等的金币&#xff0c;吐出金币的数量服从一定的概率分布&#xff0c;而且不同臂的概率分布不同。 多臂赌博机的问题是&#xff1a;假设玩家共有N次摇地…...

Golang语法规范和风格指南(一)——简单指南

1. 前引 一个语言的规范的学习是重要的&#xff0c;直接关系到你的代码是否易于维护和理解&#xff0c;同时学习好对应的语言规范可以在前期学习阶段有效规避该语言语法和未知编程风格的冲突。 这里是 Google 提供的规范&#xff0c;有助于大家在开始学习阶段对 Golang 进行一…...

数据机构记录顺序表-笔记1

一、线性表的基本概念 数据元素&#xff1a;线性表中的基本单位&#xff0c;每个元素都是线性表的一部分。 数据项&#xff1a;数据元素的具体值。 存储位置&#xff1a;线性表中的元素在内存中的具体存储位置。 线性表按存储结构可以分为顺序表和链表两大类&#xff1a; 1.1…...

考研必备~总结严蔚敏教授《数据结构》课程的重要知识点及考点

作者主页&#xff1a;知孤云出岫 目录 1. 基本概念1.1 数据结构的定义1.2 抽象数据类型 (ADT) 2. 线性表2.1 顺序表2.2 链表 3. 栈和队列3.1 栈3.2 队列 4. 树和二叉树4.1 树的基本概念4.2 二叉树 5. 图5.1 图的基本概念5.2 图的遍历 6. 查找和排序6.1 查找6.2 排序 7. 重点考…...

【数据分享】国家级旅游休闲街区数据(Excel/Shp格式/免费获取)

之前我们分享过从我国文化和旅游部官网整理的2018-2023年我国50个重点旅游城市星级饭店季度经营状况数据&#xff08;可查看之前的文章获悉详情&#xff09;&#xff01;文化和旅游部官网上也分享有很多与旅游相关的常用数据&#xff0c;我们基于官网发布的名单文件整理得到全国…...

Linux开发:进程间通过Unix Domain Socket传递数据

进程间传递数据的方式有很多种,Linux还提供一种特殊的Socket用于在多进程间传递数据,就是Unix Domain Socket(UDS)。 虽然通过普通的Socket也能做到在多进程间传递数据,不过这样需要通过协议栈层的打包与拆包,未免有些浪费效率,通过UDS,数据仅仅通过一个特殊的sock文件…...

Redis基础教程(九):redis有序集合

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; &#x1f49d;&#x1f49…...

Servlet与Servlet容器

什么是Servlet? Servlet是Java EE&#xff08;现称Jakarta EE&#xff09;中的一个组件&#xff0c;通常用于创建动态Web内容。Servlet是运行在Web服务器上的Java程序&#xff0c;它处理客户端的请求并生成响应。Servlet的核心功能是处理HTTP请求和响应。下面是一个servlet例…...

腾讯centos mysql安装

腾讯centos mysql安装 腾讯云提供了一系列的云计算服务&#xff0c;包括操作系统、数据库、服务器等。在腾讯云上安装CentOS操作系统和MySQL数据库可以按照以下步骤进行&#xff1a; 登录腾讯云控制台&#xff08;登录 - 腾讯云&#xff09;。在控制台页面上方的搜索框中输入…...

c_各个unsigned int 和 int的取值范围

bool, uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t 取值范围分别是什么&#xff1f; 定义形式&#xff1a; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef unsigned long uint64_…...

C#/WPF 自制截图工具

在日常使用电脑办公时&#xff0c;我们经常遇到需要截图然后保存图片&#xff0c;我们往往需要借助安装截图工具才能实现&#xff0c;现在我们通过C#自制截图工具&#xff0c;也能够轻松进行截图。 我们可以通过C#调用WindousAPI来实现截图&#xff0c;实例代码如下&#xff1a…...

以腾讯为例,手把手教你搭建产品帮助中心

一个精心设计的产品帮助中心对于提高用户满意度和体验至关重要。腾讯&#xff0c;作为全球领先的互联网企业&#xff0c;通过其多样化的产品线&#xff08;包括微信、QQ、腾讯游戏、腾讯视频等&#xff09;吸引了亿万用户。下面将以腾讯为例&#xff0c;向您展示如何搭建一个高…...

计算机网络概述--自我学习用

计算网络体系概述 相关问题 计算机网络为什么要分层&#xff1f;计算机网络是怎么分层的&#xff1f;三种计算机网络模型的关系是什么&#xff1f;每一层分别包含哪些协议&#xff1f;计算机网络中&#xff0c;数据如何在各层中传播&#xff1f;数据在网络各层中的存在形式是…...

超级好用的java http请求工具

kong-http 基于okhttp封装的轻量级http客户端 使用方式 Maven <dependency><groupId>io.github.kongweiguang</groupId><artifactId>kong-http</artifactId><version>0.1</version> </dependency>Gradle implementation …...

在原有的iconfont.css文件中加入新的字体图标

前言&#xff1a;在阿里图标库中&#xff0c;如果你没有这个字体图标的线上项目&#xff0c;那么你怎么在本地项目中的原始图标文件中添加新的图标呢&#xff1f; 背景&#xff1a;现有一个vue项目&#xff0c;下面是这个前端项目的字体图标文件。现在需要新开发功能页&#x…...

使用 ESP32-WROOM + DHT11 做个无屏温湿度计

最近梅雨天&#xff0c;有个房间湿度很大&#xff0c;而我需要远程查看温湿度&#xff0c;所以无所谓有没有显示屏&#xff0c;某宝上的温湿度计都是带屏的&#xff0c;如果连WIFI查看温湿度操作也比较麻烦&#xff0c;还需要换电池&#xff0c;实在不能满足我的需求&#xff0…...

如何使用 SwiftUI 构建 visionOS 应用

文章目录 前言WindowsVolumes沉浸式空间结论 前言 Apple Vision Pro 即将推出&#xff0c;现在是看看 SwiftUI API 的完美时机&#xff0c;这使我们能够将我们的应用程序适应 visionOS 提供的沉浸式世界。苹果表示&#xff0c;构建应用程序的最佳方式是使用 Swift 和 SwiftUI。…...

InspireFace-商用级的跨平台开源人脸分析SDK

InspireFace-商用级的跨平台开源人脸分析SDK InspireFaceSDK是由insightface开发的⼀款⼈脸识别软件开发⼯具包&#xff08;SDK&#xff09;。它提供了⼀系列功能&#xff0c;可以满⾜各种应⽤场景下的⼈脸识别需求&#xff0c;包括但不限于闸机、⼈脸⻔禁、⼈脸验证等。 该S…...

华为HCIP Datacom H12-821 卷24

1.单选题 企业大楼有大量员工通常都在上班时在大厅开始接入到公司的WLAN网络,随着每位员工走到各自的工位过程中,每个人的移动端叶通过漫游的方式漫游到各自的网络覆盖区域。为了尽量保证每个终端的IP地址是固定的,建议的做法是? A、配置VLAN Pool并配置顺序算法 B、…...

TikTok马来西亚直播网络怎么配置?

TikTok是一款全球流行的社交媒体应用&#xff0c;在东南亚地区拥有大量用户。在马来西亚这个多元化的国家&#xff0c;配置高效稳定的直播网络对TikTok的运营至关重要。 配置马来西亚直播网络的必要性 广泛的地理覆盖&#xff1a;马来西亚包括大片陆地和众多岛屿&#xff0c;网…...

基于若依的文件上传、下载

基于若依实现文件上传、下载 文章目录 基于若依实现文件上传、下载1、前端实现-文件上传1.1 通用上传分析1.2 修改实现上传接口 2、后端实现-文件上传3、后端实现-文件下载4、前端实现-文件下载 官网其实也写了&#xff0c;但是我是自己改造封装了一下&#xff0c;再次迈向全栈…...

论文回顾 | CVPR 2021 | How to Calibrate Your Event Camera | 基于图像重建的事件相机校准新方法

论文速览 | CVPR 2021 | How to Calibrate Your Event Camera | 基于图像重建的事件相机校准新方法 1 引言 在计算机视觉和机器人领域,相机校准一直是一个基础而又重要的问题。传统的相机校准方法主要依赖于从已知校准图案中提取角点,然后通过优化算法求解相机的内参和外参。这…...

高级java每日一道面试题-2024年7月1日

题目&#xff1a;请解释 Java 中的内存泄漏&#xff0c;并说明如何检测和避免内存泄漏。 答案&#xff1a; 内存泄漏指的是程序中不再使用的对象&#xff0c;由于某些原因没有被垃圾回收器回收&#xff0c;仍然占据着内存空间&#xff0c;导致可用内存逐渐减少&#xff0c;最…...

当需要对多个表进行联合更新操作时,怎样确保数据的一致性?

文章目录 一、问题分析二、解决方案三、示例代码&#xff08;以 MySQL 为例&#xff09;四、加锁机制示例五、测试和验证六、总结 在数据库管理中&#xff0c;经常会遇到需要对多个表进行联合更新的情况。这种操作带来了一定的复杂性&#xff0c;因为要确保在整个更新过程中数据…...

数据结构-线性表的应用

目录 前言一、有序表的合并1.1 顺序表实现1.2 单链表实现 二、稀疏多项式的相加和相乘2.1 稀疏多项式的相加2.2 稀疏多项式的相乘 总结 前言 本篇文章介绍线性表的应用&#xff0c;分别使用顺序表和单链表实现有序表的合并&#xff0c;最后介绍如何使用单链表实现两个稀疏多项…...

cpp http server/client

httplib 使用httplib库 basedemo server.cpp #include "httplib.h" #include <iostream> using namespace httplib;int main(void) {Server svr;svr.Get("/hello", [](const Request& req, Response& res) {std::cout << "lo…...