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

Linux 蓝牙音频软件栈实现分析

Linux 蓝牙音频软件栈实现分析

    • 蓝牙协议栈简介
    • 蓝牙控制器探测
    • BlueZ 插件系统及音频插件

蓝牙协议栈简介

蓝牙协议栈是实现蓝牙通信功能的软件架构,它由多个层次组成,每一层负责特定的功能。蓝牙协议栈的设计遵循蓝牙标准 (由蓝牙技术联盟Bluetooth SIG 定义),支持多种蓝牙配置文件 (Profiles),以满足不同的应用场景 (如音频传输、文件传输、健康设备、键盘鼠标这样的输入输出设备等)。

蓝牙各个应用场景的实现,如音频传输、文件传输和键盘鼠标这样的输入设备,与系统中常规的这些功能的实现大为不同。如对于音频播放和录制,通过 USB 连接的音频设备,或通过 audio codec 实现的音频播放和录制,在 Linux 中,基于 ALSA 框架实现,内核通过导出设备文件向用户空间暴露相应的硬件能力。USB 键盘鼠标,在 Linux 中,基于输入设备框架实现,内核同样通过导出设备文件向用户空间暴露相应的硬件能力。

可与蓝牙协议栈类比的不是系统中常规的各个功能的实现,而是 TCP/IP 网络协议栈。在实现上,与 TCP/IP 网络协议栈类似,蓝牙协议栈不同功能的各个协议层次实现分布于硬件、Linux 操作系统内核、BlueZ 这样的蓝牙系统服务和 PulseAudio 这样系统服务中。

Bluetooth SIG 官方的蓝牙核心规范 (蓝牙核心规范 6.0) 给出的蓝牙核心系统架构如下图所示:
Bluetooth core system architecture
蓝牙协议栈的分层结构如下图所示:

+--------------------------------------------------------------------------------------------+
|                   Application Layer                                                        |
|  (Profiles: A2DP, HFP, HSP, AVRCP, HAP, BAP, ACS, ACAS, GAP, GATT, FTP, OPP, etc.)         |
+--------------------------------------------------------------------------------------------+
|                   Middleware Layer                                                         |
|  (Protocols: AVDTP, AVCTP, SDP, ATT, RFCOMM, OBEX, TCS, BNEP, etc.)    |
+--------------------------------------------------------------------------------------------+
|                   Host Controller Interface (HCI)                                          |
|  (Protocols: HCI Commands, Events, and Data)                                               |
+--------------------------------------------------------------------------------------------+
|                   Logical Link Control and                                                 |
|                   Adaptation Protocol (L2CAP)                                              |
+--------------------------------------------------------------------------------------------+
|                   Baseband Layer                                                           |
|  (Protocols: Link Manager Protocol (LMP), SCO, eSCO, ACL, ISOC, etc.)                            |
+--------------------------------------------------------------------------------------------+
|                   Radio Layer                                                              |
|  (Physical Layer: Bluetooth Radio)                                                         |
+--------------------------------------------------------------------------------------------+

蓝牙协议栈各层次简单说明如下:

  • 应用层:实现具体的蓝牙应用功能 (如音频传输、文件传输)。通过蓝牙配置文件 (Profiles) 定义设备的行为。常见的应用层协议/配置文件有 A2DP (Advanced Audio Distribution Profile,高质量音频传输),HFP (Hands-Free Profile,免提通话),HSP (Headset Profile,耳机通话),AVRCP (Audio/Video Remote Control Profile,远程控制音频/视频设备),HAP (Hearing Aid Profile,用于助听器设备),BAP (Bluetooth Audio Profile,用于通用音频设备),ACS (Audio Control Service,提供音频控制功能(如音量调节、播放控制),基于 GATT/ATT 实现,通过暴露特性(Characteristics)供应用程序使用),ACAS (Audio Stream Control Service,提供音频流管理功能(如流的创建、配置、删除),基于 GATT/ATT 实现,与 Isochronous Channels(ISOC) 协作,实现低延迟音频流传输),GATT (Generic Attribute Profile,定义基于 ATT 的服务和特性,用于数据传输,提供逻辑信道管理,支持客户端-服务器模型),GAP (Generic Access Profile,定义设备角色 (如广播者、观察者、中心设备、外围设备) 和连接流程,负责设备发现、连接建立和安全控制),FTP (File Transfer Profile,文件传输),OPP (Object Push Profile,对象推送 (如联系人、图片)),PAN (Personal Area Network Profile,个人局域网),HID (Human Interface Device Profile,人机接口设备 (如键盘、鼠标) 等。

  • 中间件层:提供高层协议和服务,支持应用层的功能实现。常见的中间件层协议有,SDP (Service Discovery Protocol,服务发现协议,用于查找设备支持的服务),RFCOMM (Radio Frequency Communication,串口仿真协议,用于模拟 RS-232 串口通信),OBEX (Object Exchange Protocol,对象交换协议,用于文件传输和数据同步),TCS (Telephony Control Protocol Specification,电话控制协议,用于语音通话),BNEP (Bluetooth Network Encapsulation Protocol,网络封装协议,用于蓝牙网络共享),AVDTP (Audio/Video Distribution Transport Protocol,音频/视频传输协议,负责音频流的传输和控制,它定义了音频流的建立、配置、启动、暂停和停止等操作),AVCTP (Audio/Video Remote Control Profile,音频/视频远程控制协议,蓝牙协议栈中的控制传输协议,负责音频/视频控制命令的传输,它定义了控制命令的封装和传输机制),ATT (Attribute Protocol,用于在 BLE 设备之间传输属性数据,提供基于客户端-服务器的数据访问机制) 等。

  • HCI 层:提供主机和蓝牙控制器之间的通信接口。负责传输命令、事件和数据。

  • L2CAP 层:提供多路复用、分段和重组功能,支持上层协议的数据传输。管理逻辑链路,提供可靠的数据传输服务。

  • 基带层:管理物理链路,处理蓝牙设备的连接和通信。负责频率跳变、数据包格式化和错误检测。常见的基带层协议有 LMP (Link Manager Protocol,链路管理协议,负责设备之间的连接建立和维护),SCO (Synchronous Connection-Oriented link,同步面向连接链路,用于语音传输),ACL (Asynchronous Connectionless link,异步无连接链路,用于数据传输),ISOC (Isochronous Channels,提供同步数据传输通道,支持低延迟的音频流传输)。

  • 射频层:负责蓝牙无线电信号的发送和接收。处理频率跳变、调制和解调。使用蓝牙无线电协议,主要工作在 2.4 GHz ISM 频段。

蓝牙协议栈相对于 TCP/IP 网络协议栈,其各层之间并不是那么的各自独立,而是紧密关联的。蓝牙协议栈中与音频相关的有 4 个用于不同场景的子协议栈,它们分别是用于传输高质量音频流的 A2DP,包括 A2DP -> AVDTP -> L2CAP -> ACL;用于通过蓝牙远程控制音频/视频设备的 AVRCP,包括 AVRCP -> AVCTP -> L2CAP -> ACLA2DPAVRCP 常协作实现蓝牙音频;用于语音通话的 HFP/HSP,包括 HFP/HSP -> SCO/eSCO;用于低功耗蓝牙的 HAP/BAP,包括 HAP/BAP -> ACS/ACAS -> GATT -> ATT -> GAP -> ISOC。 除 HAP/BAP 协议栈外,其它的都是经典蓝牙的协议栈。

类比于 TCP/IP 网络协议栈中的 RTP/RTCP 协议,A2DP/AVDTP 协议类似于 RTP 协议,AVRCP/AVCTP 协议类似于 RTCP 协议,L2CAP/ACL 协议类似于 UDP 协议,只是它们是可靠传输协议。

在实现上,HCI 及更下层的协议无疑由 Linux 内核或硬件实现。应用层和中间件层协议的实现则常随着时间的流逝而变化。低功耗蓝牙是比较新的蓝牙标准,对低功耗蓝牙的支持是从 BlueZ 5.55 版本开始逐步添加的。对于 Linux 内核,则是从 Linux 5.13 版本开始,逐步支持 Isochronous Channels。

在早期的 BlueZ 版本中,PulseAudio 这样的音频服务需要将音频流数据通过 Unix Domain Socket 发送给 BlueZ,再由 BlueZ 通过 A2DP 协议发送给蓝牙硬件设备。从 BlueZ 5.0 开始,BlueZ 的音频功能(如 A2DP)逐渐被移出 BlueZ 核心代码库,转而由 PipeWire 或 PulseAudio 这样的系统音频服务器直接处理音频流的传输。BlueZ 不再直接处理音频流数据,而是通过 D-Bus 接口 与音频后端(如 PipeWire 或 PulseAudio)交互。AVDTP 的实现由音频后端负责,BlueZ 仅提供蓝牙协议栈的核心功能(如设备管理、连接管理)。音频后端负责音频流的编码、解码和传输。音频后端直接与蓝牙硬件交互,处理音频流数据。

蓝牙控制器探测

BlueZ 是 Linux 官方蓝牙协议栈,提供对蓝牙无线通信标准的全面支持。核心协议方面,它支持 L2CAP(逻辑链路控制与适配协议),RFCOMM(串口仿真协议),SDP(服务发现协议),HCI(主机控制器接口)。配置文件方面,它支持 A2DP(高级音频分发),AVRCP(音视频远程控制),HFP(免提协议),HID(人机接口设备),PAN(个人局域网)。硬件设备类型方面,它支持音频设备,如蓝牙耳机、音箱;输入设备,如键盘、鼠标;网络连接,如蓝牙 PAN;物联网,如智能家居设备。它还提供一系列与蓝牙设备管理控制有关的工具程序,如 bluetoothd,蓝牙守护进程,管理设备和服务;bluetoothctl,命令行工具,用于设备配对、连接等操作;hcitool,配置蓝牙适配器及查询设备信息;sdptool,浏览和发布 SDP 服务记录。

BlueZ 整个项目的代码丰富而复杂,这里主要关注与蓝牙音频有关的逻辑。

BlueZ 系统服务 bluetoothd 启动时,执行 adapter_init() 函数初始化蓝牙适配器,这个调用过程如下:

#0  adapter_init () at src/adapter.c:10337
#1  0x0000aaaaaaac3398 in main (argc=<optimized out>, argv=<optimized out>) at src/main.c:1216

adapter_init() 函数定义 (位于 src/adapter.c) 如下:

int adapter_init(void)
{dbus_conn = btd_get_dbus_connection();mgmt_primary = mgmt_new_default();if (!mgmt_primary) {error("Failed to access management interface");return -EIO;}if (getenv("MGMT_DEBUG"))mgmt_set_debug(mgmt_primary, mgmt_debug, "mgmt: ", NULL);DBG("sending read version command");if (mgmt_send(mgmt_primary, MGMT_OP_READ_VERSION,MGMT_INDEX_NONE, 0, NULL,read_version_complete, NULL, NULL) > 0)return 0;error("Failed to read management version information");return -EIO;
}

adapter_init() 函数访问一下 DBus 连接,调用 mgmt_new_default() 函数创建并初始化 struct mgmt 对象,设置 struct mgmt 的调试配置,并调用 mgmt_send() 函数向 struct mgmt 发送一个读取版本号的请求。

mgmt_new_default() 函数定义 (位于 src/shared/mgmt.c) 如下:

struct mgmt {int ref_count;int fd;bool close_on_unref;struct io *io;bool writer_active;struct queue *request_queue;struct queue *reply_queue;struct queue *pending_list;struct queue *notify_list;unsigned int next_request_id;unsigned int next_notify_id;bool need_notify_cleanup;bool in_notify;void *buf;uint16_t len;uint16_t mtu;mgmt_debug_func_t debug_callback;mgmt_destroy_func_t debug_destroy;void *debug_data;
};. . . . . .
static void mgmt_set_mtu(struct mgmt *mgmt)
{socklen_t len = 0;/* Check if kernel support BT_SNDMTU to read the current MTU set */if (getsockopt(mgmt->fd, SOL_BLUETOOTH, BT_SNDMTU, &mgmt->mtu,&len) < 0) {/* If BT_SNDMTU is not supported then MTU cannot be changed and* MTU is fixed to HCI_MAX_ACL_SIZE.*/mgmt->mtu = HCI_MAX_ACL_SIZE;return;}if (mgmt->mtu < UINT16_MAX) {uint16_t mtu = UINT16_MAX;/* Try increasing the MTU since some commands may go* over HCI_MAX_ACL_SIZE (1024)*/if (!setsockopt(mgmt->fd, SOL_BLUETOOTH, BT_SNDMTU, &mtu,sizeof(mtu)))mgmt->mtu = mtu;}
}struct mgmt *mgmt_new(int fd)
{struct mgmt *mgmt;if (fd < 0)return NULL;mgmt = new0(struct mgmt, 1);mgmt->fd = fd;mgmt->close_on_unref = false;mgmt->len = 512;mgmt->buf = malloc(mgmt->len);if (!mgmt->buf) {free(mgmt);return NULL;}mgmt->io = io_new(fd);if (!mgmt->io) {free(mgmt->buf);free(mgmt);return NULL;}mgmt->request_queue = queue_new();mgmt->reply_queue = queue_new();mgmt->pending_list = queue_new();mgmt->notify_list = queue_new();if (!io_set_read_handler(mgmt->io, can_read_data, mgmt, NULL)) {queue_destroy(mgmt->notify_list, NULL);queue_destroy(mgmt->pending_list, NULL);queue_destr

相关文章:

Linux 蓝牙音频软件栈实现分析

Linux 蓝牙音频软件栈实现分析 蓝牙协议栈简介蓝牙控制器探测BlueZ 插件系统及音频插件蓝牙协议栈简介 蓝牙协议栈是实现蓝牙通信功能的软件架构,它由多个层次组成,每一层负责特定的功能。蓝牙协议栈的设计遵循蓝牙标准 (由蓝牙技术联盟,Bluetooth SIG 定义),支持多种蓝牙…...

PySide(PyQt),使用types.MethodType动态定义事件

以PySide(PyQt)的图片项为例&#xff0c;比如一个视窗的场景底图是一个QGraphicsPixmapItem&#xff0c;需要修改它的鼠标滚轮事件&#xff0c;以实现鼠标滚轮缩放显示的功能。为了达到这个目的&#xff0c;可以重新定义一个QGraphicsPixmapItem类&#xff0c;并重写它的wheelE…...

2.5 python接口编程

在现代软件开发的复杂生态系统中&#xff0c;不同系统、模块之间的交互协作至关重要。接口编程作为一种关键机制&#xff0c;定义了组件之间的通信规范与交互方式。Python 凭借其卓越的灵活性、丰富的库资源以及简洁易读的语法&#xff0c;在接口编程领域占据了重要地位&#x…...

SpringData JPA事务管理:@Transactional注解与事务传播

文章目录 引言一、事务基础概念二、Transactional注解详解2.1 基本用法2.2 属性配置2.3 类级别与方法级别 三、事务传播行为详解3.1 REQUIRED&#xff08;默认&#xff09;3.2 REQUIRES_NEW3.3 其他传播行为 四、事务隔离级别五、事务最佳实践5.1 正确设置事务边界5.2 合理使用…...

第2章、WPF窗体及其属性

1、窗体的宽与高。 2、启动窗体设置 3、窗体的启动位置设置 4、窗体图标更换 5、应用程序的图标更改 6、 7、窗体属性汇总&#xff1a; AllowsTransparency 类型: bool 描述: 该属性决定窗口是否可以有透明效果。如果设置为true&#xff0c;窗口的背景必须设置为Transpar…...

关于ModbusTCP/RTU协议对接Ethernet/IP(CIP)协议的方案

IGT-DSER智能网关模块支持西门子、倍福(BECKHOFF)、罗克韦尔AB&#xff0c;以及三菱、欧姆龙等各种品牌的PLC之间通讯&#xff0c;支持Ethernet/IP(CIP)、Profinet(S7)&#xff0c;以及FINS、MC等工业自动化常用协议&#xff0c;同时也支持PLC与Modbus协议的工业机器人、智能仪…...

WPF 与 GMap.NET 结合实现雷达目标动态显示与地图绘制

概述 雷达上位机是雷达系统中用于数据可视化、分析和控制的核心软件。本文将介绍如何使用 C# 和 WPF 框架开发一个雷达上位机程序&#xff0c;主要功能包括&#xff1a; 显示目标轨迹&#xff1a;在界面上实时绘制雷达探测到的目标轨迹。点击显示详细信息&#xff1a;用户点击…...

A SURVEY ON POST-TRAINING OF LARGE LANGUAGE MODELS——大型语言模型的训练后优化综述——第2部分

3、微调&#xff08;上一部分内容&#xff09; 4、LLMs的对齐 大型语言模型&#xff08;LLMs&#xff09;中的对齐涉及引导模型输出以符合人类预期和偏好&#xff0c;特别是在安全关键或用户面对的应用程序中。本章讨论了实现对齐的三个主要范式&#xff1a; 带有反馈的人工…...

pytest快速入门 - 目录:半天掌握pytest

1 pytest快速入门 - 目录 本系列文章将快速的带领用户进入pytest领域&#xff0c;通过阅读本专栏&#xff0c;用户将可以熟练掌握pytest的基本用法&#xff0c;同时对测试前置条件的构造、后置条件的清理等有较深入的了解&#xff0c;特别是后置条件的执行完备度有一个认识。 …...

2018年全国职业院校技能大赛高职组-计算机网络应用竞赛竞赛样题C卷

目录 总体规划 模块二:设备基础信息配置 模块三:网络搭建与网络冗余备份方案部署 模块四:移动互联网搭建与网优 模块五:出口安全防护与远程接入 总体规划 CII教育公司在进行企业大学信息化建设的过程中,为了保证北京校区、广州校区与本部校区的日常OA办公通信等关键业务,…...

某大厂自动化工程师面试题

一些大厂的自动化工程师面试题汇总: 基础知识类 请解释什么是PLC(可编程逻辑控制器)?什么是PID控制?它在自动化系统中的作用是什么?请描述一下工业4.0的基本概念。编程与控制系统类 你熟悉哪些PLC编程语言?请举例说明。如何在SCADA系统中实现数据采集和监控?请解释一下…...

L1-7 统一命名规范(java)

你所在的公司刚刚招收了几位程序员&#xff0c;然而这些程序员之前在不同的公司工作&#xff0c;所以他们习惯的变量命名规范可能存在差异&#xff0c;需要让他们都习惯公司要求的命名规范&#xff0c;然而这样可能会降低他们的工作效率。 你的上司找到了你&#xff0c;希望你…...

ES6回顾:闭包->(优点:实现工厂函数、记忆化和异步实现)、(应用场景:Promise的then与catch的回调、async/await、柯里化函数)

闭包讲解 ES6回顾&#xff1a;闭包->(优点&#xff1a;实现工厂函数、记忆化和异步实现&#xff09;、&#xff08;应用场景&#xff1a;Promise的then与catch的回调、async/await、柯里化函数&#xff09; 以下是与 JavaScript 闭包相关的常见考点整理&#xff0c;结合 Pro…...

zend server试用分析

文件&#xff1a;ZendServer-2021.4.1-multi-php-Windows_x86.exe 安装后可以试用30天&#xff0c;想分析下限制原理, 根据安装日志&#xff0c;发现了2个关键的文件&#xff1a; ZendServer\gui\module\Configuration\src\Configuration\License\Wrapper.php ZendServer\gu…...

C# NX二次开发:在多个体的模型中如何实现拉伸操作布尔减

大家好&#xff0c;今天接着上一篇拉伸文章去讲。 UF_MODL_create_extruded1 (view source) uf_list_p_tobjectsInputList of objects to be extruded.char *taper_angleInputTaper angle (in degrees).char *limit [ 2 ]InputLimit of extrusion. This is declared as: char …...

15 | 定义简洁架构 Store 层的数据类型

提示&#xff1a; 所有体系课见专栏&#xff1a;Go 项目开发极速入门实战课&#xff1b;欢迎加入 云原生 AI 实战 星球&#xff0c;12 高质量体系课、20 高质量实战项目助你在 AI 时代建立技术竞争力&#xff08;聚焦于 Go、云原生、AI Infra&#xff09;&#xff1b;本节课最终…...

GitLab多种场景下的备份与迁移指南

GitLab备份与迁移完全指南 GitLab作为一个完整的DevOps平台,其数据对于组织至关重要。无论是版本升级、服务器迁移还是灾难恢复,掌握GitLab的备份和迁移技术都是系统管理员的必备技能。本文将详细介绍GitLab的备份策略和各种场景下的迁移方法。 目录 GitLab备份基础知识Omn…...

2.3 滑动窗口专题:最大连续1的个数 III(LeetCode 1004)

1. ​题目链接 1004. 最大连续1的个数 III - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/max-consecutive-ones-iii/ 2. ​题目描述 给定一个二进制数组 nums 和一个整数 k&#xff0c;允许将最多 k 个 0 翻转为 1&#xff0c;求翻转后最长的连续 1 …...

【微服务】Nacos 配置动态刷新(简易版)(附配置)

文章目录 1、实现方法2、配置依赖 yaml3、验证效果 1、实现方法 环境&#xff1a;Nacos、Java、SpringBoot等 主要是在boostrap.yaml中的data-id属性下配置refresh:true来实现动态更新 2、配置依赖 yaml 具体的版本参考官方的说明&#xff1a;官方版本说明 <!--读取boo…...

六十天前端强化训练之第二十天React Router 基础详解

欢迎来到编程星辰海的博客讲解 看完可以给一个免费的三连吗&#xff0c;谢谢大佬&#xff01; 目录 一、核心概念 1.1 核心组件 1.2 路由模式对比 二、核心代码示例 2.1 基础路由配置 2.2 动态路由示例 2.3 嵌套路由实现 2.4 完整示例代码 三、关键功能实现效果 四、…...

高级java每日一道面试题-2025年2月26日-框架篇[Mybatis篇]-Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式 ?

如果有遗漏,评论区告诉我进行补充 面试官: Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式 ? 我回答: 在Java高级面试中讨论MyBatis如何将SQL执行结果封装为目标对象并返回的过程时&#xff0c;我们可以从过程细节和映射形式两个方面来综合解答这个问…...

人工智能之数学基础:如何将线性变换转换为矩阵?

本文重点 在机器学习中,常用的理论就是线性变换,线性变化一定有对应的矩阵表示,非线性变换是不具备这个性质的,那么现在如果有一个线性变换T那么如何知道它对应的矩阵呢? 线性变换的本质 我们知道线性变换相当于一个函数,而矩阵也是一个函数,所以线性变换一定存在一个…...

用 DeepSeek 构建 Vue.js 底层架构:高效协作与问题解决实践

文章目录 1. **DeepSeek 与 Vue.js 的完美协作**2. **问题背景**3. **问题分析与解决**3.1 **动态路由未正确生成**3.2 **路由路径配置错误**3.3 **路由嵌套问题**3.4 **通配符路由未配置** 4. **DeepSeek 的核心价值** 在现代前端开发中&#xff0c;Vue.js 以其简洁的语法和灵…...

社交网络分析实战(NetworkX分析Twitter关系图)

目录 社交网络分析实战(NetworkX分析Twitter关系图)1. 引言2. 项目背景与意义3. 数据集生成与介绍3.1 数据集构成3.2 数据生成方法3.3 数据集示例4. 社交网络分析理论4.1 节点度数与度分布4.2 网络密度4.3 中心性指标5. GPU加速在社交网络分析中的应用6. PyQt GUI与交互式可视…...

UI自动化:seldom框架和Selenium

以下是关于 seldom框架 和 Selenium 的对比解析及结合使用的详细说明&#xff0c;帮助理解二者的定位、功能差异和应用场景&#xff1a; 1. 核心定位 工具定位Selenium浏览器自动化工具库&#xff0c;提供直接操控浏览器的底层API&#xff08;如点击、输入、获取元素等&#x…...

深入探讨RAID 5的性能与容错能力:实验与分析(磁盘阵列)

前言—— 本实验旨在探讨 RAID 5 的性能和容错能力。通过创建 RAID 5 阵列并进行一系列读写性能测试及故障模拟&#xff0c;我们将观察 RAID 5 在数据冗余和故障恢复方面的表现&#xff0c;以验证其在实际应用中的可靠性和效率。 首先说明&#xff1a;最少三块硬盘, 使用 4 块…...

EG82088串口边缘计算网关

EG82088串口边缘计算网关 EG8208是一款专业级8路独立隔离型RS485通讯控制器,通过Modbus及JSON支持、灵活的TCP/IP和UDP切换、内置监控自诊断等特性,广泛应用于工业自动化、楼宇管理等领域,为用户提供卓越的数据采集和设备管理解决方案。 接口类型&#xff1a;8RS485/8DO/1LAN协…...

蓝桥杯备赛-二分-技能升级

问题描述 小蓝最近正在玩一款 RPG 游戏。他的角色一共有 NN 个可以加攻击力的技能。 其中第 ii 个技能首次升级可以提升 AiAi​ 点攻击力, 以后每次升级增加的点数 都会减少 Bi。「AiBi⌉Bi​。「Bi​Ai​​⌉ (上取整) 次之后, 再升级该技能将不会改变攻击力。 现在小蓝可以…...

【实战ES】实战 Elasticsearch:快速上手与深度实践-附录-2-性能调优工具箱

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 附录-性能调优工具箱 2-Elasticsearch 性能调优工具箱深度指南一、性能诊断工具集1.1 实时监控工具1.2 慢查询分析 二、硬件与基础架构优化2.1 存储方案选型2.2 JVM调优参数 三、索引…...

电子招采软件系统,如何实现10年可追溯审计

一、在当前经济环境下&#xff0c;中小企业面临着巨大的生存压力&#xff0c;传统产业的数字化转型迫在眉睫。AI技术为企业的低成本高效发展提供了新机会&#xff0c;混合办公成为新常态&#xff0c;数据安全法的深入落实则进一步推动企业重视数据安全。区块链存证技术凭借独特…...