经典蓝牙(BT/EDR)蓝牙配对与连接
经典蓝牙的连接过程包括跳频,扫描,配置交换等过程。对ACL链路以及sco的连接过程也做详细的分析。
1. 为什么不配对便无法建立连接?
任何无线通信技术都存在被监听和破解的可能,蓝牙SIG为了保证蓝牙通信的安全性,采用认证的方式进行数据交互。同时为了保证使用的方便性,以配对的形式完成两个蓝牙设备之间的首次通讯认证,经配对之后,随后的通讯连接就不必每次都要做确认。所以认证码的产生是从配对开始的,经过配对,设备之间以PIN码建立约定的link key用于产生初始认证码,以用于以后建立的连接。
所以不配对,两个设备之间便无法建立认证关系,无法进行连接及其之后的操作,所以配对在一定程度上保证了蓝牙通信的安全,当然这个安全保证机制是比较容易被破解的,因为现在很多个人设备没有人机接口,所以PIN码都是固定的而且大都设置为通用的0000或者1234之类的,所以很容易被猜到并进而建立配对和连接。
2. 蓝牙的连接过程
现在的蓝牙芯片供应商提供的技术支持能力相当强大,有完整的硬件和软件解决方案。对于应用而言,提供了固件用于实现底层协议栈,提供了profile库及源代码规范了各种应用,开发人员只要专注于应用程序开发就可以了。对于蓝牙底层的一些东西往往不甚了了。以前我也是这样子的,最近在做一个自动搜索以实现自动连接的应用,发现还是需要了解一些底层的机制的。
我们可以很容易的进行操作在一个手机和免提设备之间建立连接,那么这个连接是怎么建立起来的呢?
首先,主设备(master,即发起连接的设备)会寻呼(page)从设备(slave,接收连接的设备),master会以跳频的方式去寻呼slave,slave会固定间隔地去扫描(scan)外部寻呼,即page scan,当scan 到外部page时便会响应response该page,这样两个设备之间便会建立link的连接,即ACL链路的连接。当ACL 链路连接建立后,主设备会发起channel的连接请求,即L2CAP的连接,建立L2CAP的连接之后,主设备采用SDP去查询从设备的免提服务,从中得到rfcomm的通道号,然后主设备会发起rfcomm的连接请求建立rfcomm的连接。然后就建立了应用的连接。
即link establish->channel establish->rfcomm establish->connection
3. 广播数据分析
3.1. 发送广播数据包的叫广播发起者(advertisers),在广播通道接收广播数据包但没意向连接广播发起设备的叫扫描者( scanners), 需要连接到另一个设备的设备叫做 initiators,它监听可连接的广播数据包。如果advertiser正在使用一个可连接的广播事件, initiator在收到连接数据包的物理通道上发起一个连接请求,如果advertiser接受这个连接请求则这个广播事件结束,并且开始一个新的连接事件。一旦连接建立,initiator成为主设备,advertiser成为从设备。连接事件被用于在主从设备之间传输数据包。
连接过程:
广播者:广播包使用ADV_IND PDU标志;
扫描者:发送扫描请求(SCAN_REQ PDU)请求关于广播者的信息一个SCAN_REQ PDU(包含了扫描者的设备地 址), 在同一信道上回复一个SCAN_RSP PDU;
发起者: 发起者发送连接请求(CONNECT_REQ PDU)请求进入连接态,广播者确认即可以连接上。
SCAN_REQ_PDU载荷如下图所示,由ScanA(扫描设备地址)和AdvA组成(广播设备地址),ScanA是扫描设备的公共或随机地址(由TxAdd确定),AdvA是广播设备的公共或随机地址(由RxAdd确定)。
图 - 扫描请求PDU载荷
广播报文的报头中的TxAdd指示了扫描设备使用的是公共地址(Public Address)还是随机地址(Random Address)。
TxAdd = 0:公共地址。
TxAdd = 1:随机地址。
RxAdd指示了广播设备使用的是公共地址(Public Address)还是随机地址(Random Address)。
RxAdd = 0:公共地址。
RxAdd = 1:随机地址。
3.2. 扫描响应
SCAN_RSQ_PDU载荷如下图所示,由AdvA(广播设备地址)和ScanRspData组成(扫描响应数据),AdvA是广播设备的公共或随机地址(由TxAdd确定)。
图 - 扫描响应PDU载荷
广播报文的报头中的TxAdd指示了广播设备使用的是公共地址(Public Address)还是随机地址(Random Address)。
TxAdd = 0:公共地址。
TxAdd = 1:随机地址。
广播报文的长度域指示了载荷的字节数(AdvA和ScanRspData)。
3.3. SCAN_REQ和SCAN_RSP解析
3.3.1. 捕获SCAN_REQ
按照《蓝牙4.0BLE抓包(一)》中的描述进行抓包,下面是我们捕获一个心率计的SCAN_REQ包。
图4:捕获的SCAN_REQ包
3.3.2. 分析SCAN_REQ
为了方便分析,我们先取出这个SCAN_REQ包实际传输的数据,如图3中所示。心率计完整的广播报文如下:
D6 BE 89 8E 83 0C 7F 0F 72 DD DF 68 DA B5 E9 D2 CC F3 BD BF 27
在分析数据之前,再次说明:广播包含扫描请求和扫描响应,所以扫描请求和扫描响应得包格式遵循广播包的格式。
分析报文时,需要注意一下报文各个域的字节序。
3.3.2.1. 接入地址
D6 BE 89 8E:接入地址,对广播来说是固定值。注意一下这里的字节序,接入地址传输时是低字节在前的。
3.3.2.2. PDU
1). 83:广播报文报头。
bit0~bit3是0011,说明广播类型是SCAN_REQ,即扫描请求。
bit7(RxAdd)是1:说明广播设备使用的是随机地址。
bit6(TxAdd)是0:说明扫描设备使用的是公共地址。
2). 0C:长度,表示SCAN_REQ报文的长度是12个字节。
3). 7F 0F 72 DD DF 68:扫描设备的公共地址(报头里的TxAdd指示了这个地址是公共地址)。这里使用的实验设备是[艾克姆科技]的EN-nRF51DK开发板和小米3手机,扫描设备是小米3手机,在图3中可以看到该公共地址对应的是Xiao_mico_72。
4). DA B5 E9 D2 CC F3:广播设备的地址(报头里的RxAdd指示了这个地址是随机地址)。
3.3.2.3. 校验
BD BF 27:24字节CRC校验。
3.3.3. 捕获SCAN_RSP
按照《蓝牙4.0BLE抓包(一)》中的描述进行抓包,捕获一个心率计的SCAN_REQ包。
图 - 捕获的SCAN_RSP包
3.3.4. 分析SCAN_RSP
同样,在这里我们先取出SCAN_REQ包的数据,便于分析。
D6 BE 89 8E 44 06 DA B5 E9 D2 CC F3 61 6A 0F
3.3.4.1 接入地址
D6 BE 89 8E:接入地址,对广播来说是固定值。注意一下这里的字节序,接入地址传输时是低字节在前的。
3.3.4.2 PDU
1). 44:广播报文报头。
bit0~bit3是0100,说明广播类型是SCAN_RSP,即扫描响应。
bit6(TxAdd)是1:说明广播设备使用的是随机地址。
2). 06:长度,表示SCAN_ RSP报文的长度是6个字节。
3). DA B5 E9 D2 CC F3:广播设备的地址(报头里的RxAdd指示了这个地址是随机地址)。
3.3.4.3 校验
61 6A 0F:24字节CRC校验。
3.4.连接请求CONNECT_REQ
在低功耗蓝牙技术建立连接的过程中,设备都是成对出现的:master和slave设备。如果master希望与slave建立连接,master就需要发起连接请求(ConnectionRequest,CONNECT_REQ)因此master可以称之为连接发起者;同时,slave必须是可连接的并且具有解析连接请求CONNECT_REQ的能力,slave可以称之为广播者。图1是连接请求CONNECT_REQ的帧结构。
图1 CONNECT_REQ帧结构
其中,InitA是连接发起者的蓝牙设备地址,长度为6字节;AdvA是广播者的蓝牙设备地址,长度为6字节。除了InitA和AdvA之外,帧格式中最为重要的部分则是LLData,这一部分包含了在连接建立过程中所需要使用的有意义的参数。
为了更好的理解连接请求CONNECT_REQ,我们可以在日常生活中找到类似的一个例子,帮助我们理解它的含义。读者们很多应该都有过工作经验,在开始新的工作之前,都需要和雇主签署一份劳动合同,而CONNECT_REQ就是一份由“雇主”master提供的“劳动合同”,只需经过“雇员”slave确认,这份“合同”就开始生效,低功耗蓝牙技术的连接也就建立了。接下来我们就对“合同”中的各项条款逐条进行分析(如图2所示)。
图2 LLData示意图
(1)接入地址(AA:Access Address)
这份合同的第一条款就是为雇员分配一个公司内部的唯一识别码,类似于工号,雇员可以在公司内部使用这一工号;当雇员离开公司之后,唯一识别码自动失效;即使是这一雇员再次加入到这家公司,他/她的新工号也与旧的工号不同。类似的,在两个低功耗蓝牙技术设备建立连接之前,master设备负责生成接入地址,这一地址类似于一个4字节的随机数,当连接建立之后,master和slave都使用这一接入地址进行通信;当连接断开之后,接入地址自动失效。
(2)CRCInit(CRC初始值)
这份“合同”的第二条款是CRCInit,它就是雇员在公司内部的一个密钥,通过这个密钥,雇员可以访问公司内部的资源。对于低功耗蓝牙技术设备,master和slave使用CRCIinit来验证数据包的完整性。
(3)WinSize和WinOffset
合同的第三条款中规范了雇员首次来公司报到的时间以及今后每次工作的时长。WinSize和WinOffset在低功耗蓝牙技术连接中,也做了类似的定义。WinOffset定义了在CONNECT_REQ命令之后的一个通信窗口的偏移量,如图3所示。在slave设备收到CONNECT_REQ之后,slave设备需要占用一些时间、根据LLData参数进行一些相关的配置,因此,WinOffeset为slave设备进行此种操作提供了时间,transmitWindowOffset= WinOffset×1.25 ms。WinSize定义了设备每次开启收发机的窗口时间,无论是master还是slave,它们都遵循WinSize的定义,窗口时间transmitWindowSize=WinSize×1.25 ms。
因此,在CONNECT_REQ之后,第一个由master发送到slave的数据帧,我们称之为“锚点”(如图3所示),因为之后的所有的连接事件都以这一时刻为基准,呈现周期性变化。从红色框图中我们可以看到,第一个数据帧的时刻不能早于(1.25ms+transmitWindowOffset),同时也不能晚于(1.25 ms + transmitWindowOffset + transmitWindowSize)。
图3 发起连接时序图
(4)Interval, Latency & Timeout
一般情况下,人们的工作时间是朝九晚五,一周工作五天。但是在低功耗蓝牙技术的连接机制当中,我们采用了更加灵活的“弹性工作制”。对于低功耗蓝牙技术连接的弹性工作制,这里有三个参数需要了解,Interval,Lantency和Timeout。
图4 连接事件时序图
在连接建立之后,master和slave之间的数据交互我们可以称之为连接事件,连接事件的发生周期(connInterval)则是由Interval参数来进行设定,connInterval= Interval×1.25 ms, connInterval的取值范围则是在7.5 ms至4 s秒之间。因此,在确定了锚点之后,master和slave将按照connInterval确定的时间间隔进行数据的交互,如图4所示。
但是,对于低功耗蓝牙技术,低功耗的特性是需要特别考虑的,而且在实际的应用当中,不需要在每次connInterval都产生连接事件,因此引入了参数Lantancy,可以有效的减少连接事件的产生,connSlaveLatency= Latency。connSlaveLatency 定义了slave设备可以忽略多少个连续的连接事件,其不需要在这些被忽略的连接事件中侦听来自master的数据包,这也意味着slave设备不需要在每个连接事件产生的时刻都唤醒并打开射频接收机进行侦听,所以可以有效减少slave设备的功耗。这也是低功耗蓝牙技术能够实现其低功耗特性的一个重要的原因。
Timeout参数定义了连接超时的长度,connSupervisionTimeout= Timeout×10 ms,其取值范围在100 ms至32 s之间。不论是master还是slave,在其收到一个数据帧之后,如果等待了connSupervisionTimeout时长都没有下一个数据帧到来,则可以认为连接已经断开。在这里要强调的是,connSupervisionTimeout必须大于(1 + connSlaveLatency) × connInterval × 2,否则,slave设备即使是在Lantency状态,也会被误认为是连接超时,导致连接误断开。
(5)ChM & Hop
我们都知道,蓝牙使用的是跳频技术,当连接建立之后,master和slave设备就需要利用某种机制来在预先设定的信道图谱上、按照预先设定的跳频跨度进行跳频工作,信道图谱就来自ChM参数,每跳的跨度则来自于Hop参数。Hop是一个整数,取值范围在5至16之间。下面的公式提供了跳频的工作方式:
四、物理链路
同步链路(SCO): 主要用来传输对实时性要求很高的数据,比如蓝牙通话
我们可以将sco比喻为tcp/ip的udp传输模式,他的数据传输具有实时性
sco可在不被选中的情况下发送sco数据包
当数据发生错误时,不提供错误重传机制
异步链路(ACL): 主要用于传输对实时性要求不是很高的场景,比如听歌,所以a2dp就是使用的是acl的传输方
可以将acl比喻为tcp/ip的tcp传输,主要运用于对数据的实时性要求不是很高的场景
当数据发生错乱时候,会发生重传机制
注意:只有在ACL链接已经建立之后,才可以建立SCO 链接
五、ACL连接过程概述
ACL链接流程图:
ACL链接步骤(深色的为必须,浅色的为可选):
三、异步连接(ACL)连接过程步骤详解
1、
设备A通过HCI对Link Management发出HCI_Create_Connection命令,然后链接管理器LM会通过HCI返回当前的链接状态,然后LM开启呼叫设备B的操作。
2、
3、
A设备的LM发出LMP_Host_Connection_req到B设备的LM,然后LM通过HCI把这个来自A设备的连接请求发给B设备的Host层。
4、
在上面第三步操作以后,B设备会接收到来自A设备的连接请求,然后B设备会根据自身情况来作出对应的操作,一般有以下的三种操作:拒绝连接、接受连接和接受连接但是B设备修改为Master。
拒绝连接:
接受连接:
接受连接但是B设备修改为Master
5、
AFH(Adaptive Frequency Hopping)。AFH 的实现过程为设备识别、信道分类、分类信息交换、自适应跳频。
LMP(Link Manager Protocol):链路管理协议。
这一步主要是根据设备自身情况来设置跳频自适应和信道分类等功能,如果设备不支持或者不定义这些功能,那么这一步可以跳过。
6、
这一步主要是设置鉴权功能,LM将向Host请求Link key。如果设备不支持或不定义这个鉴权功能,那么可以通过这一步。
7、
在第三步发出连接请求以后,如果master设备和要连接的slave设备没有相同的link key,那么就需要配对,就是master和slave设备双方输入PIN码,然后把这个PIN码作为这次连接过程的link key,并储存好这个link key以作下次连接时使用,蓝牙的鉴权是基于link key的。
如果master和slave设备具有共同的link key,那么他们就不需要进行配对而是直接进行link key鉴权。
8、
如果上面的配对过程或鉴权成功了,就开始到数据加密过程 。下面这个图片只是显示了加密的点对点连接的设置流程。
9、
当上面那些设置流程走完以后,就要通知对方连接配置完成了,master设备的LM会发送LMP_setup_complete PDU给slave设备的LM,slave的LM产生应答,然后双方的LM再通过HCI分别通知双方的Host。
10、
如果断开连接,Host会通过HCI主动告诉LM,然后LM再通过LMP PDU来通知slave设备的LM,最后通知slave设备的Host。这个断连是单方面发起的,不需要slave设备的LM的应答,但是需要利用基带传输的ARQ机制(自动重传机制)来确认slave设备的LM是否收到了LMP_detach命令。
四、同步连接(SCO/eSCO)连接过程步骤详解
1、
master设备请求EV3、EV4、EV5同步连接
slave设备请求同步EV3、EV4、EV5同步连接
master设备请求同步连接,通过使用sco
master设备请求与老式设备进行sco同步连接
任何仅支持sco同步连接的设备请求与某个设备进行同步连接
2、
对于SCO而言,是不会进行重传的。所以对于只支持sco的耳机来说,我们可能会发现在较远距离的通话过程中就会产生杂音,这是无法避免的,这也是esco存在的原因,esco是支持重传的。
下面是master设备重新协商esco连接,即如果已存在的同步连接如果不是esco,修改当前已存在的同步连接为esco
slave设备重新协商esco连接
esco断连
sco断连
相关文章:
经典蓝牙(BT/EDR)蓝牙配对与连接
经典蓝牙的连接过程包括跳频,扫描,配置交换等过程。对ACL链路以及sco的连接过程也做详细的分析。 1. 为什么不配对便无法建立连接? 任何无线通信技术都存在被监听和破解的可能,蓝牙SIG为了保证蓝牙通信的安全性,采用…...
用 Python 从零开始创建神经网络(十四):L1 和 L2 正则化(L1 and L2 Regularization)
L1 和 L2 正则化(L1 and L2 Regularization) 引言1. Forward Pass2. Backward pass到此为止的全部代码: 引言 正则化方法旨在降低泛化误差。我们首先讨论的正则化形式是L1正则化和L2正则化。L1和L2正则化用于计算一个数值(称为惩…...
特殊的数学性质
一个数模9的结果等于它的每一位数相加和模9...
最长递增子序列&什么是继承性?C++中如何实现继承?继承的好处和注意事项有哪些?
最长递增子序列 方法一:暴力二维dp,初始状态:每个元素至少和自己构成一个上升序列,大小为1,状态转移:找到前面结尾数字小于当前数组元素的最长序列,当前位置的长度就是lenpre1. class Solutio…...
汽车IVI中控开发入门及进阶(三十五):架构QML App Architecture Best Practices
在Qt/QML工程的架构中,架构很重要,虽然本身它有分层,比如QML调用资源文件(图片等)显示GUI界面,后面的CPP文件实现界面逻辑,但是这个分类还有点粗。在实际开发中,界面逻辑也就是基于类cpp的实现,也开始使用各种面向对象的设计模式,实现更加优秀的开发架构,这点尤其在…...
面试题整理(二)
芯冰乐知识星球入口:芯冰乐...
编码及其代码
编码 形成文字所需bit点------有相应代号(编码---有好多种8/16/24/32)都已提前形成好,放哪哪就会形成那个文字 同一个文字在不同编码存的码不一样 用一种编码存的话,如果用另一种编码解析就会出现乱码 Windows默认编码为ANSI …...
python selenium(4+)+chromedriver最新版 定位爬取嵌套shadow-root(open)中内容
废话不多说,直接开始 本文以无界作为本文测试案例,抓取shadow-root(open)下的内容 shadow Dom in selenium: 首先先讲一下shadow Dom in selenium 版本的区别,链接指向这里 在Selenium 4版本 以及 chrom…...
AutoClass加载预训练实例
AutoClass 由于 Transformer 架构种类繁多,AtuoClass可以创建一个你想要的做模型架构。作为 🤗 Transformer 核心理念的一部分,使库易于使用、简单且灵活,可以AutoClass从给定的检查点自动推断和加载正确的架构。该from_pretrain…...
在 CentOS 上安装 NFS 服务器
文章目录 1. 在 CentOS 上安装 NFS 服务器1.1 安装 NFS 服务器软件包1.2 配置 NFS 共享目录1.3 配置 NFS 导出文件1.4 启动并启用 NFS 服务1.5 导出共享目录1.6 配置防火墙1.7 检查 NFS 状态 2. 在 CentOS 上安装 NFS 客户端2.1 安装 NFS 客户端软件包2.2 挂载 NFS 共享2.3 配置…...
utf8mb4_unicode_ci、utf8mb4_general_ci、utf8mb4_0900_ai_ci; Mysql 排序字符集的优缺点和选择
标题内容 Mysql的排序字符集真让人头疼,如果两个表的排序字符集不一致,还会导致在进行字段比较的时候直接报错。下面分析几个常用的字符集的优劣和选择。 utf8mb4_unicode_ci 特点 Unicode 标准兼容性高:它是基于 Unicode 标准的排序规则&a…...
星宸SSC8836Q/SSC8836Q-H
SSC8836Q产品是高度集成的多媒体片上系统(SoC)产品,适用于汽车和运动/运动相机等高分辨率智能视频录制和播放应用。 该芯片包括64位双核RISC处理器,先进的图像信号处理器(ISP),高性能的H.265/H。264/MJPEG视频编解码器,智能处理单…...
rk3576 , android14 , 编译, 卡死,android.bp , ninja
问题:我在 编译 android14 的时候, 卡死再 analysing android.bp 这里 ,卡了 3,4 个小时。肯定是有问题的。 如图&…...
3、.Net UI库:MaterialSkin - 开源项目研究文章
MaterialSkin 是一个开源的 WinForms 第三方库,提供了许多仿谷歌设计风格的组件,使得 WinForms 窗体程序更加美观。以下是 MaterialSkin 的一些关键特点和使用方法: 主要特点: 仿谷歌设计风格:MaterialSkin 提供了大量…...
2024年构建PHP应用开发环境
文章目录 前言选择合适的PHP版本安装与配置PHP环境Windows平台Linux平台macOS平台 集成Web服务器数据库连接与管理使用Composer进行依赖管理调试工具的选择代码质量管理部署与持续集成安全性考虑参考资料结语 前言 随着互联网的发展,PHP作为一门成熟的服务器端编程…...
苹果手机iPad投屏到安卓电视,不只有AirPlay一种方法,还可以无线远程投屏!
苹果品牌的设备一般都可以使用airplay功能,将一个屏幕投射到另一个屏幕上。如果是跨品牌或跨系统投屏,airplay就未必能够适应。 提供无线投屏和airplay投屏两种方式的AirDroid Cast已经推出TV版本。苹果手机或iPad可以选择无线(远程ÿ…...
什么是内网什么是外网?区别是什么
内网和外网是计算机网络中的两个基本概念,它们在定义、特点和使用场景上有显著的区别。虎观代理小二将带大家详细了解内网与外网的定义以及它们之间的主要差异,帮助读者更好地理解和应用这两种网络。 内网(局域网,LAN࿰…...
基于Springboot+Vue的在线答题闯关系统
基于SpringbootVue的在线答题闯关系统 前言:随着在线教育的快速发展,传统的教育模式逐渐向互联网教育模式转型。在线答题系统作为其中的一个重要组成部分,能够帮助用户通过互动式的学习方式提升知识掌握度。本文基于Spring Boot和Vue.js框架&…...
html css 图片背景透明
html css图标背景透明 css属性: background-color:transparent; mix-blend-mode: multiply; 完整HTML代码: <html><head><title>Test</title></head><body><div id"test" style"background-col…...
Servlet
一 Servlet Servlet (server applet) 是运行在服务端(tomcat)的Java小程序,是sun公司提供一套定义动态资源规范; 从代码层面上来讲Servlet就是一个接口 用来接收、处理客户端请求、响应给浏览器的动态资源。在整个Web应用中,Servlet主要负责接收处理请求…...
MySQL用法---MySQL Workbench创建数据库和表
1. 连接数据库 打开软件,点击左下角卡片,输入设置的数据库密码,勾选单选框 2. 了解主页面的组成部分 3. 创建数据库 先点击工具栏的创建按钮 再输入数据库名称 点击 Apply 创建 4. 创建数据表 展开数据库,在Tables上右键&…...
WordPress Elementor Page Builde 任意文件读取漏洞复现(CVE-2024-9935)
0x01 产品描述: WordPress Elementor Page Builder 是一款 WordPress 插件,它允许用户以可视化方式创建和编辑网页。0x02 漏洞描述: WordPress 的 Elementor Page Builder 插件的 PDF 生成器插件在 1.7.5 之前的所有版本中都容易受到路径遍历的攻击,包括 1.7.5 rtw_pgaepb_…...
静态链接和动态链接的特点
静态链接 链接方式:在编译时,所有依赖的库代码被直接打包到生成的可执行文件中。这意味着在程序运行时,不需要再加载任何外部库文件。 优点: 独立性强:生成的可执行文件可以在没有依赖库的系统上直接运行&am…...
内核流对象(Kernel Streaming Objects)
内核流对象(Kernel Streaming Objects)是 Windows 系统中用于处理音频、视频等流媒体数据的重要机制。让我详细解释其作用和主要组件: 1. 主要作用: c // 内核流的核心功能 - 音频/视频数据的实时处理 - 多媒体设备驱动开发 - 硬件与软件之间的数据流传…...
Java 在Json对象字符串中查找和提取特定的数据
1、在处理JSON数据时,需要提出个别字段的值,通过正则表达式提取特定的数据 public static void main(String[] args) {//定义多个JSON对象字符串类型,假设每个对象有a,b,c 字段String strJson "{\"a\":1.23,\"b\"…...
21、结构体成员分布
结构体中的成员并不是紧挨着分布的,内存分布遵循字节对齐的原则。 按照成员定义的顺序,遵循字节对齐的原则存储。 字节对齐的原则: 找成员中占据字节数最大的成员,以它为单位进行空间空配 --- 遇到数组看元素的类型 每一个成员距离…...
【深度学习】四大图像分类网络之ResNet
ResNet网络是在2015年由微软实验室中的何凯明等几位提出,在CVPR 2016发表影响深远的网络模型,由何凯明团队提出来,在ImageNet的分类比赛上将网络深度直接提高到了152层,前一年夺冠的VGG只有19层。斩获当年ImageNet竞赛中分类任务第…...
zookeeper学习
解决什么问题? 首先来分析下业务对象,才能对解决的问题进行归纳和总结。它解决的事分布式应用的问题,那么分布式应用会存在哪里问题是由它的业务特性来决定的,这些问题已是为了解决业务的问题。分布式的业务特征有哪些࿱…...
Monkey结合appium模拟操作特定界面
目录 1. 使用 Monkey 操作特定界面(通过UI标识来限制) 2. 结合 uiautomator 或 appium 定位特定元素 步骤: 3. 使用 Monkey Appium 控制特定界面点击 4. 如何结合 Appium 与 Monkey 5. 限制 Monkey 只点击固定界面上的元素 使用 --pc…...
智能指针【C++11】
文章目录 智能指针std::auto_ptr std::unique_ptrstd::shared_ptrstd::shared_ptr的线程安全问题std::weak_ptr 智能指针 std::auto_ptr 管理权转移 auto_ptr是C98中引入的智能指针,auto_ptr通过管理权转移的方式解决智能指针的拷贝问题,保证一个资源…...
plsql 执行存储过程 SYS_REFCURSOR
关键字:plsql 执行存储过程 SYS_REFCURSOR 在PL/SQL中,SYS_REFCURSOR是一种特殊的数据类型,用于表示引用游标,可以用来返回查询结果或者操作数据库中的结果集。 以下是一个使用SYS_REFCURSOR执行存储过程的例子: CR…...
git修改某次commit(白痴版)
第一步 在bash窗口运行 git rebase --interactive commitId^ 比如要改的commitId是 abcedf git rebase --interactive abcedf^键盘 按 i 或者 ins 进入编辑状态 进入insert 编辑状态 在bash窗口手动把对应commit前面的pick改为e或edit 按 esc 进入退出程序 输入 :wq 保存退出…...
设计模式:19、桥接模式
目录 0、定义 1、桥接模式的四种角色 2、桥接模式的UML类图 3、示例代码 0、定义 将抽象部门与实现部分分离,使它们都可以独立地变化。 1、桥接模式的四种角色 抽象(Abstraction):一个抽象类,包含实现者…...
闭包函数的基础知识
上期文章 1. 函数装饰器 2.闭包 2.1变量作用域 python有3种变量作用域 模块全局作用域:在类或函数外部分配定义的。函数局部作用域:通过参数或者在函数主体中定义的。第3种作用域:闭包中的变量环境 2.2全局变量和局部变量 def fun(a):print(a)print(b)fun(10)10---------…...
python3D圣诞树
import pygame import math from pygame.locals import *# 初始化Pygame pygame.init()# 设置屏幕尺寸和标题 width, height 800, 600 screen pygame.display.set_mode((width, height)) pygame.display.set_caption(3D 圣诞树)# 设置颜色 GREEN (34, 139, 34) BROWN (139,…...
博物馆导览系统方案(一)背景需求分析与核心技术实现
维小帮提供多个场所的室内外导航导览方案,如需获取博物馆导览系统解决方案可前往文章最下方获取,如有项目合作及技术交流欢迎私信我们哦~撒花! 一、博物馆导览系统的背景与市场需求 在数字化转型的浪潮中,博物馆作为文化传承和知…...
[代码随想录09]字符串2的总结
前言 处理字符串主要是有思路,同时总结方法。 题目链接 151. 反转字符串中的单词 - 力扣(LeetCode) 55. 右旋字符串(第八期模拟笔试) 一、翻转字符串里的单词 这个题目的主要思路,代码采用从后往前遍历字…...
C语言程序设计P5-3【应用函数进行程序设计 | 第三节】——知识要点:函数的嵌套调用和递归调用
知识要点:函数的嵌套调用和递归调用 视频 目录 一、任务分析 二、必备知识与理论 三、任务实施 一、任务分析 本任务要求用递归法求 n!。 我们知道n!n(n-1)(n-2)……1n(n-1)!递归公式为: 1.上面公式分解为n!n(n-1)!,即将求n!的问题变为…...
【Java】protobuf-maven-plugin主动下载protoc编译proto文件
背景: 我们hadoop的代码里,配置的是3.7.1的protocol buffer,但是编译环境上安装的是2.5.0。 能成功编译,且没有什么兼容性问题。这里非常好奇发生了什么,于是研究了一下protobuf-maven-plugin插件, 发现是他去下载的 在使用protobuf-maven-plugin插件时,我们一般会这么…...
Go学习:变量
目录 1. 变量的命名 2. 变量的声明 3. 变量声明时注意事项 4. 变量的初始化 5. 简单例子 变量主要用来存储数据信息,变量的值可以通过变量名进行访问。 1. 变量的命名 在Go语言中,变量名的命名规则 与其他编程语言一样,都是由字母、数…...
AllegroHand 四指灵巧手:机器人领域的创新力量
Allegro Hand 作为一款高性价比且适应性强的机器人四指灵巧手,凭借其四根手指和十六个独立的电流控制接头,成为机器人复杂抓握、柔性操作以及触觉传感器等研究领域的理想之选。 Allegrohand 四指灵巧手技术特点 机械结构 Allegro Hand的机械结构设计高…...
蓝桥杯准备训练(lesson3 ,c++)
变量与常量 4.1 变量的创建4.2 变量初始化4.3 变量的分类4.4 常量4.4.1 字⾯常量4.4.2 #define定义常量4.4.3 const定义常量4.5 练习练习1:买票练习2:AB问题练习3:鸡兔同笼 4.1 变量的创建 了解清楚了类型,我们使⽤类型做什么呢&…...
Conda + JuiceFS :增强 AI 开发环境共享能力
Conda 是当前 AI 应用开发领域中非常流行的环境和包管理系统,因其能够简单便捷地创建与系统资源相隔离的虚拟环境广受欢迎。 Conda 支持在不同的操作系统上重建相同的工作环境,但在环境共享复用方面仍存在一些挑战。比如,在不同机器上复用相…...
小红薯x-s算法最新补环境教程12-06更新(下)
在上一篇文章中已经讲了如何去定位x-s生成的位置,本篇文章就直接开始撸代码吧 如果没看过的话可以看:小红薯最新x-s算法分析12-06(x-s 56)(上)-CSDN博客 1、获取加密块代码 首先来到参数生成的位置&…...
强化ASPICE合规与认可度:关键策略与实践路径
确保ASPICE(Automotive SPICE)标准的合规性和认可度,是一个涉及多方面努力和持续改进的过程。以下是一些关键步骤和建议,以帮助企业实现这一目标: 一、熟悉ASPICE标准 深入阅读和理解:首先,需要…...
没有合理使用线程池,引发的生产环境BUG
引言 随着多线程和并发处理需求的增加,线程池成为了提升系统性能的重要工具。Java 提供了强大的 ThreadPoolExecutor 类,能够高效地管理线程池,减少线程创建和销毁的开销。然而,当线程池达到其最大容量时,如何优雅地处…...
异步处理与后台任务管理:在 FastAPI 中实现高级特性
异步处理与后台任务管理:在 FastAPI 中实现高级特性 目录 ⚡ 背景任务与异步处理概述🛠️ 使用 BackgroundTasks 执行后台任务🚀 异步视图函数:使用 async 和 await🔄 处理并发任务:提升应用性能与响应能…...
ceph存储池
1、存储池 1、存储池的概念 存储池就是ceph的逻辑分区,专门用来存储对象的 特点 将文件切片成对象,通过hash算法,找到存储池中的pg,池中的pg根据crush算法找到osd节点 存储中的PG数量对性能有重要的影响,过多和过少…...
STM32基于HAL库的串口接收中断触发机制和适用场景
1. HAL_UART_Receive_DMA函数 基本功能 作用:启动一个固定长度的 DMA 数据接收。特点: 需要预先指定接收数据的长度(Size 参数)。DMA 会一直工作直到接收到指定数量的数据,接收完成后触发 HAL_UART_RxCpltCallback 回…...
如何查看电脑的屏幕刷新率?
1、按一下键盘的 win i 键,打开如下界面,选择【系统】: 2、选择【屏幕】-【高级显示设置】 如下位置,显示屏幕的刷新率:60Hz 如果可以更改,则选择更高的刷新率,有助于电脑使用起来界面更加流…...