网络安全 - DOS
1.1.1 摘要
最近网络安全成了一个焦点,除了国内明文密码的安全事件,还有一件事是影响比较大的——Hash Collision DoS(通过Hash碰撞进行的拒绝式服务攻击),有恶意的人会通过这个安全漏洞让你的服务器运行巨慢无比,那他们是通过什么手段让服务器巨慢无比呢?我们如何防范DoS攻击呢?本文将给出详细的介绍。
1.1.2 正文
在介绍Hash Collision DoS攻击之前,首先让我们复习一下哈希表(Hash table)。
哈希表(Hash table,也叫散列表),是根据关键码值(Key/Value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做哈希函数(它的好坏将关系到系统的性能),存放记录的数组叫做哈希表。
大家知道哈希函数在计算哈希值时不可以避免地会出现哈希冲突。
假设我们定义了一个哈希函数hash(),m代表未经哈希计算的原始键,而h是m经过哈希函数hash()计算后得出的哈希值。
现在我们对原始键m1和m2进行哈希计算就可以获取相应的哈希值分别为:hash(m1)和hash(m2)。
如果原始键m1=m2,那么将可能得到相同的哈希值,但是键m1!=m2也可能得到相同的哈希值,那么就发生了哈希冲突(Hash collision),在大多数的情况下,哈希冲突只能尽可能地减少,而无法完全避免。
当发生哈希冲突时,我们可以使用冲突解决方法解决冲突,而主要的哈希冲突解决方法如下:
开放地址法
再哈希法
链地址法
建立一个公共溢出区
当发生哈希冲突时,我们的确可以采用以上的方法解决哈希冲突,但我们能不能尽可能避免哈希冲突的出现呢?如果哈希冲突被减少到微乎其微,那么我们系统性能将得到很大提高,我们通过使用冲突几率更低的算法计算哈希值。
一般情况衡量一种算法的好坏是通过它的最优,一般和最差情况的时空复杂度来衡量算法好坏的。
在理想情况下,哈希表插入、查找和删除一个元素操作的时间复杂度都为O(1),那么插入、查找和删除n个元素的时间复杂度就为O(n),任何一个数据项可以在一个与哈希表长度无关的时间内计算出一个哈希值(Key),然后根据哈希值(Key)定位到哈希表中的一个槽中(术语bucket,表示哈希表中的一个位置)。最理想情况是我们在长度为n的哈希表中插入n个元素,而且经过哈希计算后它们的哈希值恰好均匀地分配到哈希表的每个槽中完全没有冲突,这的确太理想了。但这不符合实际情况,由于我们无法预知插入元素的个数,而且哈希表的长度也是有限的,所以说哈希冲突是无法避免的。
图1 哈希表时间复杂度
碰撞解决大体有两种思路,第一种策略是根据某种原则将被碰撞数据定为到其它槽中,例如开放地址法的线性探索,如果数据在插入时发生了碰撞,则顺序查找这个槽后面的槽,将其放入第一个没有被占有的槽中;第二种策略是每个槽不只是只能容纳一个数据项的位置,而是一个可容纳多个数据项的数据结构(例如链表或红黑树),所有碰撞的数据以某种数据结构的形式组织起来(线性探索:di = 1,2,3,…,m – 1)。
图2 开放地址法
不论使用哪种碰撞解决策略,都导致插入、查找和删除的操作的时间复杂度不再是O(1)。以查找为例:不能通过哈希值(Key)定位到槽就结束,还需要比较原始键(即未经过哈希的Key)是否相等,如果不相等,则使用与插入相同的算法继续查找,直到找到匹配的值或确认数据不在哈希表中。
.NET是使用第一种策略解决哈希冲突,它根据某种原则将碰撞数据定位到其他槽中。
而PHP是使用单链表存储碰撞的数据,因此实际上PHP哈希表的平均查找复杂度为O(L),其中L为桶链表的平均长度;而最坏复杂度为O(N),此时所有数据全部碰撞,哈希表退化成单链表。下图是PHP中正常哈希表和退化哈希表的示意图。
图3 正常哈希表
图4 退化哈希表
通过上图正常哈希表我们发现在正常情况下,哈希值分配的均匀冲突几率很低,而退化的哈希表中全部数据都在同一个槽上发生了冲突,这将导致数据插入、查找和删除的时间复杂度变为O(n2),由于时间复杂度提升了一个数量级,因此会消耗大量CPU资源,导致系统无法及时响应请求,从而达到拒绝服务攻击(DoS)的目的。
.NET中哈希表的实现
数据结构
在.NET中定义一个结构体bucket来表示槽,它只包含三个字段,具体代码如下:
/// <summary>
/// Defines hash bucket.
/// </summary>
private struct bucket
{/// <summary>/// The hask key./// </summary>public object key;/// <summary>/// The data value./// </summary>public object val;/// <summary>/// The key has hash collision./// </summary>public int hash_coll;
}
当发生冲突时,线性探索再散列在处理的过程中容易产生记录的二次聚集,而.NET通过使用再哈希和动态增加哈希表长度来减少再发生哈希冲突。
/// <summary>
/// Rehashes the specified newsize.
/// </summary>
/// <param name="newsize">The newsize.</param>
private void rehash(int newsize)
{this.occupancy = 0;// Creates a new bucket.Hashtable.bucket[] newBuckets = new Hashtable.bucket[newsize];for (int i = 0; i < this.buckets.Length; i++){Hashtable.bucket bucket = this.buckets[i];if ((bucket.key != null) && (bucket.key != this.buckets)){this.putEntry(newBuckets, bucket.key, bucket.val, bucket.hash_coll & 0x7fffffff);}}Thread.BeginCriticalRegion();this.isWriterInProgress = true;// Changes the bucket.this.buckets = newBuckets;this.loadsize = (int)(this.loadFactor * newsize);this.UpdateVersion();this.isWriterInProgress = false;Thread.EndCriticalRegion();
}
通过上面的rehash()方法我们知道当发生冲突时,.NET通过再哈希和增大哈希表的长度来避免再发生冲突。
哈希算法
现在让我们看看.NET使用什么哈希算法,查看Object.GetHashCode()方法,具体代码如下:
public virtual int GetHashCode()
{return InternalGetHashCode(this);
}
我们发现Object.GetHashCode()方法调用了另一个方法InternalGetHashCode(),我们进一步查看InternalGetHashCode()方法,发现它映射到CLR中的一个方法ObjectNative::GetHashCode,具体实现代码如下:
FCIMPL1(INT32, ObjectNative::GetHashCode, Object* obj) { CONTRACTL { THROWS; DISABLED(GC_NOTRIGGER); INJECT_FAULT(FCThrow(kOutOfMemoryException);); MODE_COOPERATIVE; SO_TOLERANT; } CONTRACTL_END; VALIDATEOBJECTREF(obj); DWORD idx = 0; if (obj == 0) return 0; OBJECTREF objRef(obj); HELPER_METHOD_FRAME_BEGIN_RET_1(objRef); // Set up a frame // Invokes another method to create hash code.idx = GetHashCodeEx(OBJECTREFToObject(objRef)); HELPER_METHOD_FRAME_END(); return idx;
}
FCIMPLEND
该方法的实现并不复杂,但我们很快就发现其实该方法里再调用GetHashCodeEx()方法,它才是具体的哈希算法的实现,这里就不做详细的介绍因为实现代码很长,如果大家想查看它的C++源代码请点这里。
现在主流编程语言都采用的哈希算法是DJB(DJBX33A),而.NET中的NameValueCollection.GetHashCode()方法就是使用DJB算法。
DJB的算法实现核心是通过给哈希值(Key)乘以33(即左移5位再加上哈希值)计算哈希值,接下来让我们看一下DJB算法的实现吧!
/// <summary>
/// Uses DJBX33X hash function to hash the specified value.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The hash string</returns>
public static uint DJBHash(string value)
{if (string.IsNullOrEmpty(value)){throw new ArgumentNullException("The hash value can't be empty.");}uint hash = 5381;for (int i = 0; i < value.Length; i++){// The value of ((hash << 5) + hash) the same as // the value of hash * 33.hash = ((hash << 5) + hash) + value[i];}}
我们看到DJB算法实现十分简单,但它却是十分优秀的哈希算法,它生成的哈希值冲突几率很低,接下来让我们看一下.NET中String.GetHashCode()方法的实现——DEK算法。
/// <summary>
/// Returns a hash code for this instance.
/// </summary>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms
/// and data structures like a hash table.
/// </returns>
public override unsafe int GetHashCode()
{// Pins the heap address, so GC can't collect it.fixed (char* str = ((char*)this)){char* chPtr = str;int num = 0x15051505;int num2 = num;int* numPtr = (int*)chPtr;for (int i = this.Length; i > 0; i -= 4){// Uses DEK to generate hash code.num = (((num << 5) + num) + (num >> 0x1b)) ^ numPtr[0];if (i <= 2){break;}// Uses DEK to generate hash code.num2 = (((num2 << 5) + num2) + (num2 >> 0x1b)) ^ numPtr[1];numPtr += 2;}return (num + (num2 * 0x5d588b65));}
}
String类中重写了GetHashCode()方法,由于GetHashCode()会涉及到一些指针操作,所以把该方法定义为unsafe表示不安全上下文,也许有人会奇怪C#中还能像C/C++中的指针操作吗?我们要在C#中使用指针操作,这时fixed关键字终于派上用场了。fixed 关键字是用来pin住一个引用地址的,因为我们知道CLR的垃圾收集器会改变某些对象的地址,因此在改变地址之后指向那些对象的引用就要随之改变。这种改变是对于程序员来说是无意识的,因此在指针操作中是不允许的。否则,我们之前已经保留下的地址,在GC后就无法找到我们所需要的对象(fixed详细介绍请参考这里)。
哈希碰撞攻击
通过前面介绍.NET中GetHashCode()方法,现在我们对于其中的实现算法有了初步的了解,由于哈希冲突的原理就是针对具体的哈希算法来构造数据,使得所有数据都发生碰撞。
但如何构造数据呢?首先让我们看一个例子,假设我们往一个类型为NameValueCollection的对象中插入数据。
图5 插入数据
通过上图我们发现插入1000个数据只需88 ms,当插入2000个数据需时345 ms,随着插入数据规模的增大我们发现插入时间越来越长,哈希表的插入时间复杂度不是O(n)吗?大家肯定知道这是由于发生哈希冲突导致时间复杂度无法达到线性。
这里我们使用了一个简单方法构造冲突数据——蛮力法。(效率低)
由于蛮力法效率低,所以我们采用更加高效的方法中途相遇攻击(meet-in-the-middle attack)或等效子串(equivalent substrings)来构造冲突数据。
等效子串:
如果哈希函数具有这样的特性,当两个字符串的哈希值发生冲突,例如:hash(“string1”)=hash(“string2”),那么由这两个子串在同一位置上构成的字符串也发生哈希冲突,例如:hash(“prefixstring1postfix”)=hash(“prefixstring2postfix”)。
假设“EZ”和“FY”在哈希函数中发生冲突,那么字符串“EzEz”,“EzFY”,“FYEz”,“FYFY”两两之间也发生冲突。大家想查看使用等效子串的例子点这里。
中途相遇攻击:
如果在一个给定的哈希函数中不存在等效子串,那么蛮力法似乎是唯一的解决办法了。但我们前面介绍蛮力法效率低,明显的以32位为例这种方式命中目标的概率是1 /(2 ^ 32)。
现在我们只需计算16位哈希值,那么命中目标的概率是1/(2^16),这样命中几率大大的提高了,而且构造数据时间也缩短了。
我们使用等效子串方法把字符串分成两部分,前缀子串(长度为n)和后缀子串(长度为m),接着我们枚举前缀子串的哈希值,并且使得它们的哈希值相等。
现在我们通过异或运算使得枚举前缀子串的哈希值都相等,首先我们让前缀子串乘以1041204193再经过DJB33计算哈希值。也许有人会问为什么要乘以1041204193呢?
由于1041204193 * 33 = 34359738369
二进制值:00000000000000000000000000000000001(使用Int32)
我们知道1041204193 * 33 = 1,那么现在的前缀子串的哈希值只与它的字符相关,这将导致冲突几率增大了。
HashBack()方法的示意代码如下:
/// <summary>
/// The hash back function.
/// </summary>
/// <param name="tmp">The string need to hash back.</param>
/// <param name="end">The hash back value.</param>
/// <returns>The hash back string.</returns>
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
private static unsafe int HashBack(string tmp, int end)
{int hash = end;fixed (char* str = tmp){char* suffix = str;int length = tmp.Length;for (; length > 0; length -= 1){hash = (hash ^ suffix[length - 1]) * 1041204193;}return hash;}
}
我们看到HashBack()方法包含两个参数,一个是要计算哈希值的字符串,而另外一个就是最后发生冲突的哈希值。
接来下我们让实现DJB33哈希函数示意代码如下:
/// <summary>
/// The hash function with DJB33 algorithm.
/// </summary>
/// <param name="tmp">The string need to hash.</param>
/// <returns>The hash value.</returns>
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
private static unsafe int Hash(string tmp)
{int hash = 5381;fixed (char* str = tmp){char* p = str;int tmpLenght = tmp.Length;for (; tmpLenght > 0; tmpLenght -= 1){hash = ((hash << 5) + hash) ^ *p++;}return hash;}
}
现在我们完成了HashBack()和Hash()方法,首先我们使用HashBack()方法计算出前缀子串的哈希值,然后再使用Hash()方法找出和前缀子串发生冲突的子串,最后把前缀和后缀拼接起来就构成了冲突字符串了。
也许大家听起来有点别扭,那么让我们通过具体的例子来说明吧!
假设我们找到前缀“BIS”,而且HashBack(“NBJ”) = 147958270,然后我们通过暴力方法找出了和前缀有冲突的后缀Hash(“SKF0FTG”) = 147958270,接着我们把它们拼接起来计算Hash(“NBJ” + “SKF0FTG”) = 6888888,我们看到拼接起来的字符串计数出来的哈希值是我们事先已经指定好的,所以我们可以通过这种方法不断构造冲突数据。
接着我们使用以上的冲突数据进行插入测试,一开始运行插入数据CPU的消耗就开始变得大了,曾经一度消耗到100%那时机器根本动不了,所以无法截图。
图7 哈希冲突测试
防御
限制CPU时间
这是最简单的方法可以减少此类攻击的影响,它通过减少CPU请求时间将被允许参加。对于PHP可以设置max_input_time参数值;在IIS(ASP.NET)中,可以通过设置“关机时间限制”值(默认90s)。
限制POST请求参数个数
本次微软推出的安全性更新是通过限制 ASP.NET处理 HTTP POST 请求時最多只能接受1000个参数个。(补丁)
如果我们的Web应用程序需要接受超过1000个参数,可以通过设置WebConfig中MaxHttpCollectionKeys的值来修改最多限制数,具体设置如下:
<!--Setting Max Http post value-->
<appSettings><add key="aspnet:MaxHttpCollectionKeys" value="1001" />
</appSettings>
限制POST请求长度
使用随机的哈希算法
由于我们事先知道使用的哈希算法,所以构造冲突数据更加有针对性,但一旦才有随机哈希算法我们没有办法预知使用算法,所以冲突数据很难构造,但不幸的是许多主流的编程语言都是采用非随机哈希算法,除了Perl之外,像.NET,Java,Ruby,PHP和Python等都是采用非随机算法。
1.1.3 总结
本文通过引入哈希表,接着介绍哈希表的实现和发生哈希冲突时处理的方法,然后针对具体的哈希算法构造冲突数据(等效子串和中途相应),最后介绍该如何防御Hash Denial Of Service 攻击。
由于我们事先知道使用的哈希算法,所以构造冲突数据更加有针对性,所以通过使用随机哈希算法可以更加有效防御Hash Denial Of Service 攻击,估计许多语言将会重新设计它们的哈希函数。
相关文章:

网络安全 - DOS
1.1.1 摘要 最近网络安全成了一个焦点,除了国内明文密码的安全事件,还有一件事是影响比较大的——Hash Collision DoS(通过Hash碰撞进行的拒绝式服务攻击),有恶意的人会通过这个安全漏洞让你的服务器运行巨慢无比&…...

【强化学习】Stable-Baselines3学习笔记
【强化学习】Stable-Baselines3学习笔记 Stable-Baselines3是什么安装ExampleReinforcement Learning Tips and TricksVecEnv相关在stablebaselines中使用自定义环境 Stable-Baselines3是什么 Stable Baselines3(简称SB3)是一套基于PyTorch实现的强化学习…...
前端真实面试题自用
一、写在前面 笔者,经过计算机学硕考研的失败后,想谋求一份前端工作实在是太难了。一方面,确实曾经学习过的东西很久没有拾起,另一方面,对于前端面经还是记忆不深刻,特地写此贴记录笔者在真实前端面试中遇…...

vue3和springboot使用websocket通信
前端端口:9090 后端端口:8080 vue3 引入依赖: npm install sockjs-client stomp/stompjs vue页面 <template><div><h1>WebSocket 示例</h1><button click"sendMessage">发送消息</button>…...
JS 解构、数组扩展符和模板字符串的常见用法
文章目录 解构1. 对象解构2. 数组解构 数组扩展符模板字符串 解构 1. 对象解构 想把对象中的属性赋值给变量时, 需要一次一次的赋值,很麻烦。而对象解构, 就是把对象的结构拆解开, 然后把拆解后的属性自动赋值给匹配的变量。 (1) 对象属性赋值变量的传统写法&…...

低代码开源项目Joget的研究——Joget7社区版安装部署
大纲 环境准备安装必要软件配置Java配置JAVA_HOME配置Java软链安装三方库 获取源码配置MySql数据库创建用户创建数据库导入初始数据 配置数据库连接配置sessionFactory编译下载tomcat启动下载aspectjweaver移动jw.war文件编写脚本运行 测试参考资料 Joget,作为一款开…...
Golang 为什么没有注解?
Go 的哲学是:“少就是多,显式优于隐式。”注解虽然方便,但会违背 Go 追求简洁和清晰的设计理念。 什么是注解?为什么看起来很实用? 注解的定义:注解是一种特殊的元信息,用于修饰代码(如类、方法、字段等),让程序或工具在运行时或编译时解析和处理这些信息。例如: …...

Visual Studio Code(VS Code)配置C/C++环境
一、Visual Studio Code安装 Visual Studio Code,下文中简称为VS Code的详细安装方法请参考VSCode安装教程(超详细)-CSDN博客 二、MinGW编译器下载与配置 1、MinGW介绍 MinGW(Minimalist GNU for Windows)是一款用于Windows 平台的轻…...

LabVIEW软件开发的未来趋势
LabVIEW软件开发的未来趋势可以从以下几个方面来分析: 1. 与AI和机器学习的深度结合 趋势:LabVIEW正在向集成AI和机器学习方向发展,尤其是在数据处理、预测性维护和自动化控制领域。 原因:AI技术的普及使得实验和工业场景中的…...
Node.js 助力前端开发:自动化操作实战
前端开发中,重复性任务如新建文件、配置路由、生成组件等,往往耗时且容易出错。借助 Node.js 的强大能力,我们可以实现开发过程中的自动化操作,提高效率。 文章目录 自动生成 router 配置文件自动生成组件模板动态构建导航菜单自…...
HuggingFace peft LoRA 微调 LLaMA
1. 安装必要库 pip install transformers peft accelerate2. 加载 LLaMA 模型和分词器 从 Hugging Face Transformers 加载预训练的 LLaMA 模型和分词器。 from transformers import AutoModelForCausalLM, AutoTokenizer# 加载 LLaMA 模型和分词器 model_name "meta-…...
记-编译magisk_v22
1) 下载源码 git clone gitgitee.com:MayuriNFC/Magisk.git 使用国内镜像站 2) 切换标签: git checkout v22.0 3)下载/更新依赖 git submodule initgit sumodule update 4)下载对应ndk(自动下载出错了,用了手动下载), wget -c https://dl.google.com/android/reposito…...
前端登录业务
1.用户登录成功拿到token,放在请求拦截器的请求头中,调用户接口才可以获取到用户信息,存储到仓库中,以便其他组件使用用户信息 2.退出登录需要清空用户数据,以及本地存储,调退出登录接口告诉服务器当前toke…...

项目2路由交换
背景 某学校为满足日常教学生活需求,推动数字校园的建设,学校有办公楼和学生宿舍楼和服务器集群三块区域,请合理规划IP地址和VLAN,实现企业内部能够互联互通现要求外网能通过公网地址访问服务器集群,学生和老师能正常…...

易语言 OCR 文字识别
一.引言 文字识别,也称为光学字符识别(Optical Character Recognition, OCR),是一种将不同形式的文档(如扫描的纸质文档、PDF文件或数字相机拍摄的图片)中的文字转换成可编辑和可搜索的数据的技术。随着技…...
云手机+YouTube:改变通信世界的划时代技术
随着科技的不断进步,手机作为人们生活中不可或缺的工具,也在不断地更新换代。近年来,一个名为“油管云手机”的全新产品正在引起广泛的关注和讨论。作为一个运用最新科技实现的新型手机,它在通信领域带来了全新的体验和革命性的变…...

C++-----------映射
探索 C 中的映射与查找表 在 C 编程中,映射(Map)和查找表(Lookup Table)是非常重要的数据结构,它们能够高效地存储和检索数据,帮助我们解决各种实际问题。今天,我们就来深入探讨一下…...

清空DNS 缓存
如果遇到修改了host文件,但是IP和域名的映射有问题的情况,可以尝试刷新DNS缓存。 ipconfig/flushdns win建加R建,然后输入cmd,然后回车 然后回车,或者点击确定按钮。 出现如下所示标识清空DNS 缓存成功。...

计算机网络习题( 第3章 物理层 第4章 数据链路层 )
第3章 物理层 一、单选题 1、下列选项中,不属于物理层接口规范定义范畴的是( )。 A、 接口形状 B、 引脚功能 C、 传输媒体 D、 信号电平 正确答案: C 2、在物理层接口特性中,用于描述完成每种功能的事件发…...

UE5 崩溃问题汇总!!!
Using bundled DotNet SDK version: 6.0.302 ERROR: UnrealBuildTool.dll not found in "..\..\Engine\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.dll" 在你遇到这种极奇崩溃的BUG ,难以解决的时候。 尝试了N种方法,都不行的解决方法。…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...

cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践
作者:吴岐诗,杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言:融合数据湖与数仓的创新之路 在数字金融时代,数据已成为金融机构的核心竞争力。杭银消费金…...

【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制
目录 节点的功能承载层(GATT/Adv)局限性: 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能,如 Configuration …...