2025-01-01 NO2. XRHands 介绍
文章目录
- 软件配置
- 1 XR Hands 简介
- 2 XRHand
- 2.1 Pose
- 2.2 Handedness
- 3 XRHandJoint
- 3.1 XRHandJointID
- 3.2 XRHandJointTrackingState
- 4 XRHandSubsystem
- 4.1 数据属性
- 4.1.1 UpdateSuccessFlags
- 4.1.2 UpdateType
- 4.2 处理器管理:注册和注销
- 4.3 更新手部数据:`TryUpdateHands` 方法
- 4.3.1 检查运行,交由第三方处理
- 4.3.2 手部状态追踪与更新
- 4.3.3 数据预处理和处理器
- 4.3.4 动态更新和手势支持
- 4.3.5 回调处理
软件配置
- Unity 版本:Unity6000.0.26
- XRHands 版本:1.5.0
1 XR Hands 简介
XR Hands 包定义了允许从支持手部跟踪的设备访问手部跟踪数据的 API。要访问手部跟踪数据,还必须启用实现 XR 手部跟踪子系统的提供程序插件。

XR Hand 套件提供:
-
XR Hand Subsystem :定义用于手部跟踪数据的 XR 子系统接口。
-
OpenXR HandTracking feature:此功能为 OpenXR 提供程序插件实现
XRHandSubsystem
。在项目中同时安装了 OpenXR 和 XR Hand 软件包,就可以访问手部数据。其他提供程序插件必须更新以实现XRHandSubsystem
,然后才能在使用它们时访问手部数据。 -
Open XR Meta Aim Hand:此功能将来自 XR_FB_hand_tracking_aim 扩展的数据提供给 OpenXR 规范。此扩展提供基本的手势识别。
-
XR Hand:单个跟踪手的数据。
-
XR Hand Joint:手部单个关节或其他跟踪点的数据。
-
Meta Aim Hand:来自 Meta Aim 手 OpenXR 功能的捏合和瞄准手势数据。
注意:
XR Hands 包定义了用于手部跟踪的 API,但本身并未实现该功能。要在目标平台上使用手部跟踪,您还需要该平台的单独提供程序插件包,该插件包已更新以向 XR Hand Subsystem(该包定义的子系统)提供手部跟踪数据。
2 XRHand
代表来自 XRHandSubsystem
的手数据对象,用于管理和表示手的状态和关节信息。它包含了关于手的信息和操作,例如获取手部关节、手部位姿和手部跟踪状态。
该类不被直接创建,而是通过 XRHandSubsystem.leftHand
和 XRHandSubsystem.rightHand
属性来访问。
public struct XRHand : IEquatable<XRHand>
{// 获取手的根位姿,位于手腕部位。public Pose rootPose { get; }// 该手是左手还是右手public Handedness handedness { get; }// 当前手的根位姿和关节是否被追踪public bool isTracked { get; }// 返回指定 ID 的关节数据// 由于关节数据存储在本地的 NativeArray 中,调用此方法时,会获取到最新的手数据。public XRHandJoint GetJoint(XRHandJointID id) { ... }...
}
2.1 Pose
Pose
是 Unity 中用于表示物体在三维空间中的位置和旋转,封装了 Vector3
和 Quaternion
的数据结构,分别用于存储位置和旋转,适合用于表示游戏对象、虚拟角色、手部模型等在空间中的姿势。
public struct Pose : IEquatable<Pose>
{public Vector3 position; // 位置public Quaternion rotation; // 旋转// 将当前 Pose 应用到一个给定的 Pose/Transform 上,通常用于将 Pose 从一个坐标系转换到另一个坐标系public Pose GetTransformedBy(Pose lhs) { ... }public Pose GetTransformedBy(Transform lhs) { ... }// 公共属性public Vector3 forward { get; }public Vector3 right { get; }public Vector3 up { get; }public Vector3 forward { get; }
}
2.2 Handedness
用于表示左右手:
// Decompiled with JetBrains decompiler
// Type: UnityEngine.XR.Hands.Handedness
// Assembly: Unity.XR.Hands, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: A6E3BCB6-F905-44B3-8327-8AFFABC5770A
// Assembly location: P:\Unity Project\Learning\XRHands-Learning\Library\ScriptAssemblies\Unity.XR.Hands.dll#nullable disable
namespace UnityEngine.XR.Hands
{/// <summary>/// Denotes which hand this joint is on./// </summary>public enum Handedness{Invalid,Left,Right,}
}
3 XRHandJoint
表示 XR 中手部关节的结构体,封装了与手部关节相关的多种信息,例如关节的 位置、旋转、半径、线速度、角速度 等。
[StructLayout(LayoutKind.Sequential)]
public struct XRHandJoint : IEquatable<XRHandJoint>
{public XRHandJointID id { get; } // 关节唯一标识符public Handedness handedness { get; } // 属于哪只手public XRHandJointTrackingState trackingState { get; } // 关节追踪状态// 尝试获取该关节的半径(如果有)。// 返回 true 表示成功获取,false 表示未能获取到有效数据。// 成功时,radius 参数将被赋值为关节的半径。public bool TryGetRadius(out float radius) { ... }// 尝试获取该关节的 姿势(位置和旋转)。// 如果姿势数据有效,返回 true,并将姿势信息赋值给 pose 参数。// 如果无效,则返回 false 并将 pose 设置为 Pose.identity。public bool TryGetPose(out Pose pose) { ... }// 尝试获取该关节的 线速度。// 如果线速度数据有效,返回 true,并将线速度赋值给 linearVelocity 参数。// 如果无效,则返回 false,并将 linearVelocity 设置为 Vector3.zero。public bool TryGetLinearVelocity(out Vector3 linearVelocity) { ... }// 尝试获取该关节的 角速度。// 如果角速度数据有效,返回 true,并将角速度赋值给 angularVelocity 参数。// 如果无效,则返回 false,并将 angularVelocity 设置为 Vector3.zero。public bool TryGetAngularVelocity(out Vector3 angularVelocity) { ... }...
}
3.1 XRHandJointID
XR Hand 将手部关节分为 26 种,包括指关节、指尖、手腕和手掌。

XR Hand 使用 XRHandJointID
枚举类表示该 26 个 Joint:
// Decompiled with JetBrains decompiler
// Type: UnityEngine.XR.Hands.XRHandJointID
// Assembly: Unity.XR.Hands, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: A6E3BCB6-F905-44B3-8327-8AFFABC5770A
// Assembly location: P:\Unity Project\Learning\XRHands-Learning\Library\ScriptAssemblies\Unity.XR.Hands.dll#nullable disable
namespace UnityEngine.XR.Hands
{/// <summary>/// The ID of this joint./// </summary>public enum XRHandJointID{Invalid = 0,BeginMarker = 1,Wrist = 1,Palm = 2,ThumbMetacarpal = 3,ThumbProximal = 4,ThumbDistal = 5,ThumbTip = 6,IndexMetacarpal = 7,IndexProximal = 8,IndexIntermediate = 9,IndexDistal = 10, // 0x0000000AIndexTip = 11, // 0x0000000BMiddleMetacarpal = 12, // 0x0000000CMiddleProximal = 13, // 0x0000000DMiddleIntermediate = 14, // 0x0000000EMiddleDistal = 15, // 0x0000000FMiddleTip = 16, // 0x00000010RingMetacarpal = 17, // 0x00000011RingProximal = 18, // 0x00000012RingIntermediate = 19, // 0x00000013RingDistal = 20, // 0x00000014RingTip = 21, // 0x00000015LittleMetacarpal = 22, // 0x00000016LittleProximal = 23, // 0x00000017LittleIntermediate = 24, // 0x00000018LittleDistal = 25, // 0x00000019LittleTip = 26, // 0x0000001AEndMarker = 27, // 0x0000001B}
}
例如,在 HandVisualizer 示例场景中,Left Hand Tracking 物体上关联了手的所有 XRHandJointID
。

3.2 XRHandJointTrackingState
表示正在跟踪的特定关节的值,分别有:
// Decompiled with JetBrains decompiler
// Type: UnityEngine.XR.Hands.XRHandJointTrackingState
// Assembly: Unity.XR.Hands, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: A6E3BCB6-F905-44B3-8327-8AFFABC5770A
// Assembly location: P:\Unity Project\Learning\XRHands-Learning\Library\ScriptAssemblies\Unity.XR.Hands.dllusing System;#nullable disable
namespace UnityEngine.XR.Hands
{[Flags]public enum XRHandJointTrackingState{None = 0, // 没有跟踪到数据Radius = 1, // 关节半径Pose = 2, // 关节姿势LinearVelocity = 4, // 关节线速度AngularVelocity = 8, // 关节角速度WillNeverBeValid = 16, // 永远失效,通常因为该关节不存在HighFidelityPose = 32, // 运行时精确追踪,而非基于推测或推算。通常来源于准确的传感器数据}
}
需要注意,该枚举类被标识为 [Flags],因此可以多选。
4 XRHandSubsystem
XRHandSubsystem
是一个抽象类或基类,通常由特定平台或设备的实现类继承和扩展,专门处理与手部追踪相关的数据,并提供框架来处理手部的状态、姿势、关节和手势等信息。
4.1 数据属性
public partial class XRHandSubsystem : SubsystemWithProvider<XRHandSubsystem, XRHandSubsystemDescriptor, XRHandSubsystemProvider>
{// 左、右手信息public XRHand leftHand { get; }public XRHand rightHand { get; } // 存储手部关节的布局信息(每个关节是否存在)public NativeArray<bool> jointsInLayout { get; }// 在最近一次手部数据更新过程中,左右手的哪些数据被成功更新。// 该属性每次手部数据更新时都会被更新。public UpdateSuccessFlags updateSuccessFlags { get; } // 与左、右手相关的常见手势的识别数据public XRCommonHandGestures leftHandCommonGestures { get; }public XRCommonHandGestures rightHandCommonGestures { get; }// 手部跟踪成功的回调事件public Action<XRHand> trackingAcquired;// 用于在手部数据的关节信息处理之前进行预处理。public Action<XRHandSubsystem, UpdateSuccessFlags, UpdateType> preprocessJoints;// 该回调会在手部数据更新时被调用。public Action<XRHandSubsystem, UpdateSuccessFlags, UpdateType> updatedHands;// 手部跟踪丢失的回调事件public Action<XRHand> trackingLost;...
}
回调的执行顺序为:
trackingAcquired ->
preprocessJoints ->
updatedHands ->
trackingLost。
注意:
updatedHands 事件每帧执行两次,最大化手部数据的更新频率:
- 第一次:在 MonoBehaviour.Update 事件附近执行。
- 第二次:在 Application.onBeforeRender 事件附近执行。
4.1.1 UpdateSuccessFlags
包括以下:
/// <summary>
/// 在每次手部数据更新中,哪些手部数据被成功更新。
/// </summary>
[Flags]
public enum UpdateSuccessFlags
{// 没有任何数据被成功更新None = 0,// 左手根姿势数据已成功更新LeftHandRootPose = 1 << 0,// 左手关节数据已成功更新LeftHandJoints = 1 << 1,// 右手根姿势数据已成功更新RightHandRootPose = 1 << 2,// 右手关节数据已成功更新RightHandJoints = 1 << 3,// 所有有效的数据已成功更新All = LeftHandRootPose | LeftHandJoints | RightHandRootPose | RightHandJoints
}
4.1.2 UpdateType
/// <summary>
/// The timing of a hand update during a frame.
/// </summary>
public enum UpdateType
{// 类似 MonoBehaviour.Update 时机更新Dynamic,// 类似 Application.onBeforeRender 时机更新BeforeRender
}
4.2 处理器管理:注册和注销
XRHandSubsystem
支持在手部数据处理流程中插入自定义的处理器,通过 RegisterProcessor
和 UnregisterProcessor
方法来进行管理。
public partial class XRHandSubsystem : SubsystemWithProvider<XRHandSubsystem, XRHandSubsystemDescriptor, XRHandSubsystemProvider>
{...List<IXRHandProcessor> m_Processors = new List<IXRHandProcessor>();public void RegisterProcessor<TProcessor>(TProcessor processor)where TProcessor : class, IXRHandProcessor{if (processor == null)throw new ArgumentException("Processor cannot be null.", nameof(processor));m_Processors.Add(processor);m_Processors.Sort(CompareProcessors);}public void UnregisterProcessor<TProcessor>(TProcessor processor)where TProcessor : class, IXRHandProcessor{m_Processors.Remove(processor);}...
}
处理器需要实现 IXRHandProcessor
接口,负责处理和修改手部关节数据。每个处理器可以根据自己的优先级顺序进行数据处理,这个顺序由 callbackOrder
来决定。
例如,在 HandVisualizer 场景中,Hand Visualizer 物体上挂载的 HandProcessor.cs 脚本就是一个处理器,依据 ProcessorExampleMode 来对 Hands 进行平滑或翻转处理。

4.3 更新手部数据:TryUpdateHands
方法
在 XRHandProviderUtility.cs 脚本中,m_Subsystem.TryUpdateHands() 方法被 Update() 方法调用。因此,TryUpdateHands() 方法用于每帧更新 Hands 数据。
在 XRHandProviderUtility.cs 中的 OnUpdate() 和 OnBeforeRender() 方法分别调用了 Update() 方法,因此 m_Subsystem.TryUpdateHands() 方法每帧被更新 2 次,即 4.1 节中的注意内容。

4.3.1 检查运行,交由第三方处理
如果未运行,则直接返回。
同时,向手部数据提供者发送请求,更新左右手的数据。
public virtual unsafe UpdateSuccessFlags TryUpdateHands(UpdateType updateType)
{if (!running)return UpdateSuccessFlags.None;updateSuccessFlags = provider.TryUpdateHands(updateType,ref m_LeftHand.m_RootPose,m_LeftHand.m_Joints,ref m_RightHand.m_RootPose,m_RightHand.m_Joints);...
}
4.3.2 手部状态追踪与更新
public virtual unsafe UpdateSuccessFlags TryUpdateHands(UpdateType updateType)
{...// 清除手指的状态缓存,确保每次计算时使用的是最新的数据。XRFingerShapeMath.ClearFingerStateCache(Handedness.Left);XRFingerShapeMath.ClearFingerStateCache(Handedness.Right);// 检测左右手追踪状态,判断是否触发 trackingAcquired 或 trackingLostvar wasLeftHandTracked = m_LeftHand.isTracked;var success = UpdateSuccessFlags.LeftHandRootPose | UpdateSuccessFlags.LeftHandJoints;m_LeftHand.isTracked = (updateSuccessFlags & success) == success;if (!wasLeftHandTracked && m_LeftHand.isTracked)trackingAcquired?.Invoke(m_LeftHand);else if (wasLeftHandTracked && !m_LeftHand.isTracked)trackingLost?.Invoke(m_LeftHand);var wasRightHandTracked = m_RightHand.isTracked;success = UpdateSuccessFlags.RightHandRootPose | UpdateSuccessFlags.RightHandJoints;m_RightHand.isTracked = (updateSuccessFlags & success) == success;if (!wasRightHandTracked && m_RightHand.isTracked)trackingAcquired?.Invoke(m_RightHand);else if (wasRightHandTracked && !m_RightHand.isTracked)trackingLost?.Invoke(m_RightHand);...
}
对于左手:
-
wasLeftHandTracked
:记录更新前左手的追踪状态。 -
success
:判断左手根姿势和关节数据是否成功更新。 -
m_LeftHand.isTracked
:根据success
判断左手是否成功追踪。如果左手的追踪状态发生了变化(从未追踪到追踪,或从追踪中丧失),则触发
trackingAcquired
或trackingLost
回调。
右手同理。
4.3.3 数据预处理和处理器
public virtual unsafe UpdateSuccessFlags TryUpdateHands(UpdateType updateType)
{...// 对手部关节数据进行预处理preprocessJoints?.Invoke(this, updateSuccessFlags, updateType);// 每个处理器都对关节数据进行处理for (int processorIndex = 0; processorIndex < m_Processors.Count; ++processorIndex)m_Processors[processorIndex].ProcessJoints(this, updateSuccessFlags, updateType);...
}
4.3.4 动态更新和手势支持
如果更新类型是动态(Dynamic
),并且手部数据提供者支持常见的手势数据,系统会更新不同的手势数据,例如:
- AimPose:目标对准姿势。
- GraspPose:抓握姿势。
- PinchPose:捏合姿势。
- GripPose:抓握姿势。
- …
对每种手势数据,XRHandSubsystem
会尝试从 provider
获取数据,并更新到对应的手势识别组件(m_LeftHandCommonGestures
和 m_RightHandCommonGestures
)。如果数据不可用,则调用 Invalidate
方法使手势数据失效。
public virtual unsafe UpdateSuccessFlags TryUpdateHands(UpdateType updateType)
{...if (updateType == UpdateType.Dynamic && provider.canSurfaceCommonPoseData){if (subsystemDescriptor.supportsAimPose){if (provider.TryGetAimPose(Handedness.Left, out var aimPoseLeft))m_LeftHandCommonGestures.UpdateAimPose(aimPoseLeft);elsem_LeftHandCommonGestures.InvalidateAimPose();}// 其它手势处理类似:GraspPose, PinchPose, GripPose等...}...
}
4.3.5 回调处理
在数据更新后,通过 updatedHands
或 handsUpdated
回调通知外部系统手部数据已经更新。
updatedHands
是较新的回调方法,而 handsUpdated
已经被弃用,但仍然保持兼容。
public virtual unsafe UpdateSuccessFlags TryUpdateHands(UpdateType updateType)
{...if (updatedHands != null)updatedHands.Invoke(this, updateSuccessFlags, updateType);#pragma warning disable 618if (handsUpdated != null)handsUpdated.Invoke(updateSuccessFlags, updateType); // 弃用,但保持兼容
#pragma warning restore 618return updateSuccessFlags;
}
相关文章:

2025-01-01 NO2. XRHands 介绍
文章目录 软件配置1 XR Hands 简介2 XRHand2.1 Pose2.2 Handedness 3 XRHandJoint3.1 XRHandJointID3.2 XRHandJointTrackingState 4 XRHandSubsystem4.1 数据属性4.1.1 UpdateSuccessFlags4.1.2 UpdateType 4.2 处理器管理:注册和注销4.3 更新手部数据:…...

Java开发-后端请求成功,前端显示失败
文章目录 报错解决方案1. 后端未配置跨域支持2. 后端响应的 Content-Type 或 CORS 配置问题3. 前端 request 配置问题4. 浏览器缓存或代理问题5. 后端端口未被正确映射 报错 如下图,后端显示请求成功,前端显示失败 解决方案 1. 后端未配置跨域支持 …...

未来20年在大语言模型相关研究方向--大语言模型的优化与改进
未来20年在大语言模型相关研究方向 模型性能优化 模型架构创新:研究新型的模型架构,如探索更高效的Transformer变体、融合递归神经网络(RNN)和卷积神经网络(CNN)的优点,以提高模型的性能、可扩展性和适应性,满足不同应用场景对模型效率和效果的要求。高效训练算法:开…...

[react] 纯组件优化子
有组件如下,上面变化秒数, 下面是大量计算的子组件,上面每一秒钟变化一次,这时候子组件会不断重新渲染, 浪费资源 父组件如下 import React, { memo, useEffect, useMemo, useState } from react; import type { ReactNode, FC } from react; import HugeCount from ./Te; int…...

美观强大的文件保险库Chibisafe
简介 什么是 Chibisafe ? Chibisafe 是一款用 Typescript 编写的快速文件上传服务,非常实用。它接受文件、照片、文档以及您能想到的任何内容,并返回可共享的链接,供您发送给其他人。它易于使用、易于部署、免费且开源࿰…...

详细教程:SQL2008数据库备份与还原全流程!
数据的安全性至关重要,无论是操作系统、重要文件、磁盘存储,还是企业数据库,备份都是保障其安全和完整性的关键手段。拥有备份意味着即使发生误删、系统崩溃或病毒攻击等问题,也能迅速通过恢复功能解决,避免数据丢失带…...

HTML——49.header和footer标签
<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>header和footer标签</title></head><body><!--header和footer标签:是html5中新标签--><!--header:定义文档的页眉,通常用来定义可见…...

【蓝桥杯选拔赛真题87】python输出字符串 第十五届青少年组蓝桥杯python选拔赛真题 算法思维真题解析
目录 python输出字符串 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python输出字符串 第十五届蓝桥杯青少年组python比赛选拔赛真题详细解析…...

OpenStack-Dashboard界面简单修改
OpenStack Dashboard界面替换图片 一、dashboard界面Logo的路径及文件 dashboard的Logo存放(在Controller节点)的路径: /usr/share/openstack-dashboard/openstack_dashboard/static/dashboard/img/涉及需要修改的文件(3个&…...

DevOps工程技术价值流:Ansible自动化与Semaphore集成
在DevOps的浪潮中,自动化运维工具扮演着举足轻重的角色。Ansible,作为一款新兴的自动化运维工具,凭借其强大的功能和灵活性,在运维领域迅速崭露头角。本文将深入探讨Ansible的特点、架构、工作原理,以及其应用场景&…...

【服务器】上传文件到服务器并训练深度学习模型下载服务器文件到本地
前言:本文教程为,上传文件到服务器并训练深度学习模型,与下载服务器文件到本地。演示指令输入,完整的上传文件到服务器,并训练模型过程;并演示完整的下载服务器文件到本地的过程。 本文使用的服务器为云服…...

第四届电子信息工程与数据处理(EIEDP 2025)
第四届电子信息工程与数据处理 2025 4th International Conference on Electronic Information Engineering and Data Processing 2025年1月17-19日 马来西亚 吉隆坡 重要信息 会议官网:www.eiedp.net 大会时间:2025年1月17-19日 大会地点&#…...

模型预测控制(MPC)算法介绍
模型预测控制(Model Predictive Control,MPC)是一种先进的控制策略,广泛应用于工业过程控制、机器人控制、电力系统等领域。它基于系统的模型,通过滚动优化来预测系统未来的行为,并据此确定当前的最优控制输…...

设计模式 创建型 建造者模式(Builder Pattern)与 常见技术框架应用 解析
建造者模式,又称生成器模式,是一种对象构建模式。它主要用于构建复杂对象,通过将复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建出具有不同表示的对象。该模式的核心思想是将一个复杂对象的构建过程分解为多个简单的…...

嵌入式系统中C++的基本使用方法
大家好,今天主要给大家分享一下,最近操作C++代码的控制方法。 什么是构造函数?构造函数在对象实例化时被系统自动调用,仅且调用一次。 什么是析构函数?与构造函数相反, 在对象结束其生命周期时系统自动执行析构函数。 第一个:析构函数与构造函数区别 实例代码: #inclu…...

机器人C++开源库The Robotics Library (RL)使用手册(四)
建立自己的机器人3D模型和运动学模型 这里以国产机器人天机TR8为例,使用最普遍的DH运动学模型,结合RL所需的描述文件,进行生成。 最终,需要的有两个文件,一个是.wrl三维模型描述文件;一个是.xml运动学模型描述文件。 1、通过STEP/STP三维文件生成wrl三维文件 机器人的…...

在 uni-app 中使用 wxml-to-canvas 的踩坑经验总结
在 uni-app 中使用 wxml-to-canvas 的踩坑经验总结 wxml-to-canvas 是一款非常强大的小程序工具,可以将 WXML 转换为 Canvas 绘图,用于生成海报、分享图片等。将其应用于 uni-app 项目中,可以为多端开发带来极大的便利,但也有一些…...

视频智能翻译
i68,爱六八,链接你我他 EasyVideoTrans英文视频转换成中文视频 EasyVideoTrans简要 最快的英文视频转中文方案由B站多位程序员Up主共同协作开发开源的项目在线Demo:EasyVideoTrans前端项目:https://github.com/sutro-planet/easyvideotrans-frontend后端项目:https://github…...

《Python加解密小实验:探索数据加密与解密的世界》
铺垫(1)-源码 import hashlib source "你好" # print(hashlib.md5(source.encode()).hexdigest())# 文件加解密 with open(../文件引用/index.png, rb) as file:data file.read() # print(hashlib.md5(data).hexdigest())# SHA也是摘要算法…...

C高级day四shell脚本
1.思维导图 2.终端输入一个C源文件名(.c结尾)判断文件是否有内容,如果没有内容删除文件,如果有内容编译并执行该文件。 #!/bin/bashread -p "请输入一个.c脚本名:" n if [ -s "$n" ] thenecho $n…...

android studio 写一个小计时器(版本二)
as版本:23.3.1patch2 例程:timer 在前一个版本的基本上改的,增加了继续的功能,实现方法稍微不同。 动画演示: activity_main.xml <?xml version"1.0" encoding"utf-8"?> <androidx…...

【网络安全实验室】SQL注入实战详情
如果额头终将刻上皱纹,你只能做到,不让皱纹刻在你的心上 1.最简单的SQL注入 查看源代码,登录名为admin 最简单的SQL注入,登录名写入一个常规的注入语句: 密码随便填,验证码填正确的,点击登录…...

华为,新华三,思科网络设备指令
1. 设备信息查看 华为 display version # 查看设备版本信息 display device # 查看设备硬件信息 新华三(H3C) display version # 查看设备版本信息 display device # 查看设备硬件信息 锐捷 show version …...

WebRTC线程的启动与运行
WebRTC线程运行的基本逻辑: while(true) {…Get(&msg, …);…Dispatch(&msg);… }Dispatch(Message *pmsg) {…pmsg->handler->OnMessage(pmsg);… }在执行函数内部,就是一个while死循环,只做两件事,从队列里Get取…...

Day3 微服务 微服务保护(请求限流、线程隔离、服务熔断)、Sentinel微服务保护框架、分布式事务(XA模式、AT模式)、Seata分布式事务框架
目录 1.微服务保护 1.1.服务保护方案 1.1.1 请求限流 1.1.2 线程隔离 1.1.3 服务熔断 1.2 Sentinel 1.2.1.介绍和安装 1.2.2 微服务整合 1.2.2.1 引入sentinel依赖 1.2.2.2 配置控制台 1.2.2.3 访问cart-service的任意端点 1.3 请求限流 1.4 线程隔离 1.4.1 OpenFeign整合Senti…...

第9章 子程序与函数调用
汇编语言是一种低级编程语言,它几乎是一对一地映射到计算机的机器码指令。在汇编语言中实现循环结构通常涉及到使用条件跳转指令(如 JMP、JE、JNE 等)来控制程序流程。下面我将通过一个简单的例子来讲解如何用x86汇编语言实现一个循环结构。 …...

manacher算法
Manacher 算法快速入门 Manacher 算法是一种用于寻找字符串中最长回文子串的高效算法,时间复杂度为 O(n)。 基本概念 回文 回文是一个字符串,从左到右和从右到左读都一样。 示例: 回文:"aba"、"abba"非回…...

Cocos2dx Lua绑定生成中间文件时参数类型与源码类型不匹配
这两天维护的一个项目,使用arm64-v8a指令集编译时遇到了报错,提示类型不匹配,具体报错的代码【脚本根据C源文件生成的中间文件】如下: const google::protobuf::RepeatedField<unsigned long long>& ret cobj->equi…...

为什么需要 std::call_once?
std::call_once 是 C 标准库中的一个函数,用来确保某个操作仅被执行一次,通常用于线程安全的初始化操作。它常与 std::once_flag 结合使用,后者用于标记某个操作是否已经执行过。 为什么需要 std::call_once? 在多线程程序中&am…...

ubuntu非root用户操作root权限问题-virbox挂在共享文件夹
首先讲一下,virtuallbox 挂在文件夹,操作的时候总是需要root权限,比较费劲。 这一操作其实也正对着我们在Ubuntu上的操作。 前段时间我想在ubuntu正常用户下去操作i2c,也出现了类似的问题。 后来把正常的操作加到组里面也解决了类…...