中山品牌网站设计/网站平台推广
文章目录
- 1、抛砖引玉
- 2、内核无锁队列kfifo
- 2.1 kfifo结构
- 2.2 kfifo分配内存
- 2.3 kfifo初始化
- 2.4 kfifo释放
- 2.5 kfifo入队列
- 2.6 kfifo出队列
- 2.7 kfifo的判空和判满
- 2.8 关于内存屏障
1、抛砖引玉
昨天遇到这样一个问题,有多个生产者,多个消费者,一个公共的消息队列,生产者向消息队列中写数据,消费者从消息队列中读数据,因为消息队列是临界资源,因此需要加锁
这样做的话,锁竞争太严重,必定会影响效率,有没有一种办法,消费者在从消息队列中读取数据时,不需要加锁?
当然有,就是为每个消费者都建立一个自己的消息队列,生产者共用一个消息队列。生产者互斥的向消息队列中写数据,负载均衡器将数据分发到每个消费者的消息队列中,消息消费者再从自己的消息队列中读取数据,这样就形成了单读单写,这样的消息队列有一个名字,叫ringbuffer(环形缓冲区),适用于单生产者,单消费者的场景,虽然是两个线程,但是却不用加锁,可以用数组或者链表实现
有人可能会疑问,消费者自己的消息队列(ringbuffer)也是临界资源,也会被消费者和负载均衡器共同访问,难道不需要加锁控制吗?
其实在RingBuffer中设置了两个指针,head和tail。head指向下一次读的位置,tail指向的是下一次写的位置。RingBuffer可用一个数组进行存储。 在进行读操作的时候,我们只修改head的值,而在写操作的时候我们只修改tail的值。在写操作时,我们在写入内容到buffer之后才修改tail的值,而在进行读操作的时候,我们会读取tail的值并将其赋值给copyTail。赋值操作是原子操作。所以在读到copyTail之后,从head到copyTail之间一定是有数据可以读的,不会出现数据没有写入就进行读操作的情况。同样的,读操作完成之后,才会修改head的数值;而在写操作之前会读取head的值来判断是否有空间可以用来写数据。所以,这时候tail到head-1之间一定是有空间可以写数据的,而不会出现一个位置的数据还没有读出就被写操作覆盖的情况。这样就保证了RingBuffer的线程安全性。
理论证明,在一个生产者和一个消费者的情况下,两者之间的同步无需加锁,即可并发访问。
2、内核无锁队列kfifo
在Linux当中,单生产者单消费者的应用场景有很多,例如每个socket都对应着一个接受缓冲区和发送缓冲区,上层应用向发送缓冲区写数据,再将数据拷贝到网卡,发送给对方,接受缓冲区则相反。又比如一个进程A产生数据发给另外一个进程B,进程B需要对进程A传的数据进行处理并写入文件,如果B没有处理完,则A要延迟发送。为了保证进程A减少等待时间,可以在A和B之间采用一个缓冲区,A每次将数据存放在缓冲区中,B每次冲缓冲区中取。
因此Linux中有自己的ringbuffer,不过它的名字叫kfifo,kfifo设计的非常巧妙,代码很精简,以下为kfifo的相关源码,内核版本为4.9.145
2.1 kfifo结构
struct __kfifo {unsigned int in; //数据到来时,存放数据的位置unsigned int out; //读取数据的位置unsigned int mask; //mask+1表示缓冲区data的容量,能容纳多少个元素unsigned int esize; //每个元素的大小void *data; //缓冲区的起始位置
};
请注意,这里的 in,out 均是无符号的整数类型。
2.2 kfifo分配内存
int __kfifo_alloc(struct __kfifo *fifo, unsigned int size,size_t esize, gfp_t gfp_mask)
{/** round down to the next power of 2, since our 'let the indices* wrap' technique works only in this case.*/size = roundup_pow_of_two(size);fifo->in = 0;fifo->out = 0;fifo->esize = esize;if (size < 2) {fifo->data = NULL;fifo->mask = 0;return -EINVAL;}fifo->data = kmalloc(size * esize, gfp_mask);if (!fifo->data) {fifo->mask = 0;return -ENOMEM;}fifo->mask = size - 1;return 0;
}
在为kfifo分配内存之前,需要检测传入的size是否为2的整数次幂,roundup_pow_of_two用于计算最接近且大于等于n的2的整数次幂,它的定义如下:
#define roundup_pow_of_two(n) \
( \__builtin_constant_p(n) ? ( \(n == 1) ? 1 : \(1UL << (ilog2((n) - 1) + 1)) \) : \__roundup_pow_of_two(n) \)它可以等价为以下代码,方便理解:
unsigned int roundup_pow_of_two(unsigned int n)
{if(n == 1) return 1;int i = 0;for(; n != 0; ++i){n >> 1;}return 1U << i;
}假设n为5,二进制位0101,在for循环内,需要循环3次,n向右移3位,才为0,
最后1向左移3为,二进制为1000,十进制为8,为2的整数次幂,并且离5最近且大于5
为什么要这么做呢?因为kfifo是环形队列,它的可读可写位置必然会回到初始位置,因此就需要用到取余操作,那么 m%n 在CPU看来就等价于 m-n*floor(m/n),其中乘法最终是通过加法和移位操作完成的,而除法首先转变为乘法,减法又会通过补码转变为加法,因此效率就比较低。
但是如果缓冲区的长度为2的整数次幂,m%n = m & (n - 1),只有减法和位运算,效率就提高了,所以才会将缓冲区的长度设置为2的整数次幂,并且将 mask 设置为 size(容量) - 1,方便后续进行位运算
计算完size后,接着将 in/out 指向的位置初始化为0,因为此刻队列还未准备好,里面并没有任何数据。
esize 赋值给 fifo->esize 这个是代表了队列中数据的类型的 size,比如队列数据类型如果为 int,则 esize 等于 4,队列数据类型为char,则 esize 等于 1
接着调用 kmalloc_array 接口,分配一个 esize * size 大小的空间,作为缓冲区
最后将 fifo->mask 赋值为 size - 1
分配好队列后,实际情况如下所示:
2.3 kfifo初始化
这里跟kfifo分配内存有点不同,kfifo初始化是使用自己定义的buffer,不在需要调用 kmalloc_array 接口申请空间了
int __kfifo_init(struct __kfifo *fifo, void *buffer,unsigned int size, size_t esize)
{size /= esize;size = roundup_pow_of_two(size);fifo->in = 0;fifo->out = 0;fifo->esize = esize;fifo->data = buffer;if (size < 2) {fifo->mask = 0;return -EINVAL;}fifo->mask = size - 1;return 0;
}
这里依旧需要检测传入的size是否为2的整数次幂,roundup_pow_of_two用于计算最接近且大于等于n的2的整数次幂,其他部分都大致类似
2.4 kfifo释放
void __kfifo_free(struct __kfifo *fifo)
{kfree(fifo->data);fifo->in = 0;fifo->out = 0;fifo->esize = 0;fifo->data = NULL;fifo->mask = 0;
}
释放kfifo比较简单,直接释放data缓冲区,将所有的数据都置为0即可
2.5 kfifo入队列
static inline unsigned int kfifo_unused(struct __kfifo *fifo)
{return (fifo->mask + 1) - (fifo->in - fifo->out);
}static void kfifo_copy_in(struct __kfifo *fifo, const void *src,unsigned int len, unsigned int off)
{unsigned int size = fifo->mask + 1;unsigned int esize = fifo->esize;unsigned int l;off &= fifo->mask;if (esize != 1) {off *= esize;size *= esize;len *= esize;}l = min(len, size - off);memcpy(fifo->data + off, src, l);memcpy(fifo->data, src + l, len - l);/** make sure that the data in the fifo is up to date before* incrementing the fifo->in index counter*/smp_wmb();
}unsigned int __kfifo_in(struct __kfifo *fifo,const void *buf, unsigned int len)
{unsigned int l;l = kfifo_unused(fifo);if (len > l)len = l;kfifo_copy_in(fifo, buf, len, fifo->in);fifo->in += len;return len;
}
数据入队列时,调用了unsigned int __kfifo_in(struct __kfifo *fifo, const void *buf, unsigned int len)
在函数内部首先调用了kfifo_unused
来判断当前还剩多少空间可以使用
前面我们已经提到过,fifo->mask 在初始化的时候被赋值成为 size - 1, 所以这里 (fifo->mask + 1) 就等于申请的时候的 size 值。size 的值代表着总的存储对象的个数,而每次在推数据进入 fifo 的时候,in 都会增加,取出数据的时候,out 都会增加。所以计算当前 fifo 中还剩余多少空间就使用了:
(fifo->mask + 1) - (fifo->in - fifo->out)
注意:这里的 in/out 是不断增加的无符号整形
接着会调用函数 static void kfifo_copy_in(struct __kfifo *fifo, const void *src, unsigned int len, unsigned int off)
首先还是通过 fifo->mask 得到了整个 size 的大小。然后是用:
off &= fifo->mask;
展开就是:
fifo->in = fifo->in & fifo->mask;
因为fifo->in是一直在增加的,但是缓冲区的容量是不变的,所以在写入数据之前,就需要找到具体在哪个位置写,也就是需要知道在缓冲区中,in的偏移量,因此就需要取余操作,但是呢,前面申请的空间已经是2的整数次幂,因此这里的位运算就替代了取余操作,提高了运算效率
接着判断 esize 的值,就是每个元素的占用内存的情况,如果不是 1 的话(一个字节),则需要对 off,size,len 分别乘以 esize。因为在使用 memcpy 时,需要以1个字节为单位进行数据拷贝。
举个例子:
接着使用:
l = min(len, size - off);
取得复制数据的长度 len 和 size-off(末尾的剩余空间) 之间的最小值,由是环形的缓冲区 ,所以在此处存在两种情况:
① 复制数据的长度len要小于size-off(末尾的剩余空间):
② 复制数据的长度len要大于size-off(末尾的剩余空间):
所以在这个地方,先去取一个 len 和 size-off 之间最小的那个值 l,即,先打算尝试把尾巴上能用的空间先用完,如果不够再去用从头部开始的剩余空间,这两个 memcpy 用得十分巧妙,不需要做额外的判断:
针对第一种情况(复制数据的长度len要小于size-off(末尾的剩余空间)):
第一条 memcpy:将 len 的数据 memcpy 到以 fifo->data (之前用过 kmalloc 分配的内存起始地址),加上 off 偏移(in 对应的偏移)的地方开始,copy 进 src 数据。
第二条 memcpy:len -l 等于0,memcpy 什么都不会做
针对第二种情况(复制数据的长度len要大于size-off(末尾的剩余空间)):
第一条 memcpy:和前一种情况一样
第二条 memcpy:len -l 大于0,将剩余的数据拷贝到fifo->data的头部
最终整个环形缓冲区的数据拷贝完成
最后在退出 kfifo_copy_in 后,在 __kfifo_in 函数中对 fifo->in 做累加:
fifo->in += len;
做完上述的拷贝后,对于上述两种情况,最后体现出来的是:
① 复制数据的长度len要小于等于size-off(末尾的剩余空间):
② 复制数据的长度len要大于size-off(末尾的剩余空间):
前面谈到的入队列都是out 在前,in在后,假设in在前,out在后呢?
复制数据的长度len要小于size-off(in和out之间的剩余空间):
第一条 memcpy:将 len 的数据 memcpy 到以 fifo->data,加上 off 偏移(in 对应的偏移)的地方开始,copy 进 src 数据。
第二条 memcpy:len -l 等于0,memcpy 什么都不会做
复制数据的长度len要大于size-off(in和out之间的剩余空间):
第一条 memcpy:将 len 的数据 memcpy 到以 fifo->data,加上 off 偏移(in 对应的偏移)的地方开始,copy 进 src 数据。
第二条 memcpy:len -l 等于0,memcpy 什么都不会做
到现在有人可能会有疑问,为什么在拷贝数据时为什么没有判断缓冲区是否满了呢?
其实这里调用了kfifo_unused函数计算剩余空间,如果剩余空间为0,虽然依旧会进入kfifo_copy_in函数,l = min(len, size - off),但这里是取了剩余空间和需要拷贝数据的最小值,即为0,两个memcpy什么都不会做
注意:如果拷贝的数据量大于剩余空间,会用数据将剩余的空间填充满,返回值就是拷贝了多少字节的数据
2.6 kfifo出队列
出队列和入队列的逻辑是差不多的,这里就不多赘述了
调用顺序是__kfifo_out–》__kfifo_out_peek–》kfifo_copy_out
static void kfifo_copy_out(struct __kfifo *fifo, void *dst,unsigned int len, unsigned int off)
{unsigned int size = fifo->mask + 1;unsigned int esize = fifo->esize;unsigned int l;off &= fifo->mask;if (esize != 1) {off *= esize;size *= esize;len *= esize;}l = min(len, size - off);memcpy(dst, fifo->data + off, l);memcpy(dst + l, fifo->data, len - l);/** make sure that the data is copied before* incrementing the fifo->out index counter*/smp_wmb();
}unsigned int __kfifo_out_peek(struct __kfifo *fifo,void *buf, unsigned int len)
{unsigned int l;l = fifo->in - fifo->out;if (len > l)len = l;kfifo_copy_out(fifo, buf, len, fifo->out);return len;
}
EXPORT_SYMBOL(__kfifo_out_peek);unsigned int __kfifo_out(struct __kfifo *fifo,void *buf, unsigned int len)
{len = __kfifo_out_peek(fifo, buf, len);fifo->out += len;return len;
}
2.7 kfifo的判空和判满
源代码中并没有判断空和判断满的函数,但是对于入队列时有一个计算剩余空间的函数,前面也提到过
static inline unsigned int kfifo_unused(struct __kfifo *fifo)
{return (fifo->mask + 1) - (fifo->in - fifo->out);
}
它的判满主要是看in - out 的值是等于 mask (size - 1)
对于出队列时,在__kfifo_out_peek 函数内,有l = fifo->in - fifo->out,当in和out相等时,就表示空的,也就是empty
关于in/out溢出问题
kfifo中的in和out只会一直增加,因为它俩是无符号整数,因此最终就会回到0,即使到in出现溢出,在out之前,in-out的值仍然为无符号整数,依旧能表示已经使用的buffer的长度,这点无需担心。这正是这个机制的精妙之处。
2.8 关于内存屏障
尽管单消费者和单生产者能够对kfifo的进行无锁并发访问,但是在源码中,入队列和出队列依旧使用了smp_wmb(),也就是内存屏障
编译器编译源代码时,会将源代码进行优化,将源代码的指令进行重排序,以适合于CPU的并行执行。然而,内核同步必须避免指令重新排序,优化屏障避免编译器的重排序优化操作,保证编译程序时在优化屏障之前的指令不会在优化屏障之后执行。
软件可通过读写屏障强制内存访问次序。读写屏障像一堵墙,所有在设置读写屏障之前发起的内存访问,必须先于在设置屏障之后发起的内存访问之前完成,确保内存访问按程序的顺序完成
。Linux内核提供的内存屏障API函数说明如下表。内存屏障可用于多处理器和单处理器系统,如果仅用于多处理器系统,就使用smp_xxx函数,在单处理器系统上,它们什么都不要。
内存屏障 | 含义 |
---|---|
smp_rmb | 适用于多处理器的读内存屏障 |
smp_wmb | 适用于多处理器的写内存屏障 |
smp_mb | 适用于多处理器的内存屏障 |
所以在 kfifo_copy_in 和 kfifo_copy_out 的尾部都插入了 smp_wmb() 的写内存屏障的代码
它的作用是确保 fifo->in 和 fifo->out 增加 len 的这个操作在内存屏障之后,也就是保证了在 SMP 多处理器下,一定是先完成了 fifo 的内存操作,然后再进行变量的增加。以免被优化后的混乱访问,导致策略失败
不过,多个消费者、生产者的并发访问还是需要加锁限制
最后再提一句,pthread_mutex中不包含内存屏障,而spin_lock中包含内存屏障
相关文章:

内核无锁队列kfifo
文章目录 1、抛砖引玉2、内核无锁队列kfifo2.1 kfifo结构2.2 kfifo分配内存2.3 kfifo初始化2.4 kfifo释放2.5 kfifo入队列2.6 kfifo出队列2.7 kfifo的判空和判满2.8 关于内存屏障 1、抛砖引玉 昨天遇到这样一个问题,有多个生产者,多个消费者,…...

18、XSS——cookie安全
文章目录 1、cookie重要字段2、子域cookie机制3、路径cookie机制4、HttpOnly Cookie机制5、Secure Cookie机制6、本地cookie与内存cookie7、本地存储方式 一般来说,同域内浏览器中发出的任何一个请求都会带上cookie,无论请求什么资源,请求时&…...

从零开发短视频电商 Jmeter压测示例模板详解(无认证场景)
文章目录 添加线程组添加定时器添加HTTP请求默认值添加HTTP头管理添加HTTP请求添加结果断言响应断言 Response AssertionJSON断言 JSON Assertion持续时间断言 Duration Assertion 添加察看结果树添加聚合报告添加表格察看结果参考 以压测百度搜索为例 https://www.baidu.com/s…...

C++可以函数重载而C不可以的原因
函数重载是指在同一个作用域内,可以定义多个函数,它们具有相同的名称但是参数列表不同。函数重载的主要原理是函数的签名不同,而在 C 中,函数签名包括函数的名称和参数列表。而在 C 中,函数的标识仅依赖于函数的名称&a…...

Spark常见算子汇总
创建RDD 在Spark中创建RDD的方式分为三种: 从外部存储创建RDD从集合中创建RDD从其他RDD创建 textfile 调用SparkContext.textFile()方法,从外部存储中读取数据来创建 RDD parallelize 调用SparkContext 的 parallelize()方法,将一个存在的集合&…...

【华为数据之道学习笔记】3-1 基于数据特性的分类管理框架
华为根据数据特性及治理方法的不同对数据进行了分类定义:内部数据和外部数据、结构化数据和非结构化数据、元数据。其中,结构化数据又进一步划分为基础数据、主数据、事务数据、报告数据、观测数据和规则数据。 对上述数据分类的定义及特征描述。 分类维…...

电脑版便签软件怎么设置在桌面上显示?
对于不少上班族来说,如果想要在使用电脑办公的时候,随手记录一些常用的工作资料、工作注意事项等内容,直接在电脑上使用便签软件记录是比较方便的。电脑桌面便签工具不仅方便我们随时记录各类工作事项,而且支持我们快速便捷使用这…...

【华为数据之道学习笔记】2-建立企业级数据综合治理体系
数据作为一种新的生产要素,在企业构筑竞争优势的过程中起着重要作用,企业应将数据作为一种战略资产进行管理。数据从业务中产生,在IT系统中承载,要对数据进行有效治理,需要业务充分参与,IT系统确保遵从&…...

【IC前端虚拟项目】git和svn项目托管平台的简单使用说明
【IC前端虚拟项目】数据搬运指令处理模块前端实现虚拟项目说明-CSDN博客 代码托管在gitee平台上,进去后会看到文档目录“MVU芯片前端设计验证虚拟项目”和工程目录“mvu_prj”,可以通过git来下载工程: git clone gitgitee.com:gjm9999/ic_vi…...

C++ IO库
IO类 IO对象不能拷贝和赋值 iostream 表示形式的变化: 将100转换成二进制序列 然后格式化输出 x,y共用一块内存 输出的时候用不同的方式解析同一块内存 操作 格式化:内部表示转换为相应字节序列 缓存:要输出的内容放到缓存 编码转换&…...

Springboot 项目关于版本升级到 3.x ,JDK升级到17的相关问题
由于spring 停止对2.x 版本的维护,以及 jdk 频繁发布等客观因素,现需要对已有springboot 工程做一次全面升级;已因对市面上第三方等依赖库的兼容问题; 现有工程使用哥技术栈是版本: freemarker :2.3.32 spr…...

QGraphicsView实现简易地图7『异步加载-多瓦片-无底图』
前文链接:QGraphicsView实现简易地图6『异步加载-单瓦片-无底图』 前一篇文章提到的异步单瓦片加载,是指线程每准备好一个瓦片数据后,立刻抛出信号让主线程加载。而本篇异步多瓦片加载是指线程准备好所有瓦片数据后,一起抛出信号让…...

Spring Boot学习(三十三):集成kafka
前言 下面是zookeeper和kafka的官网下载地址,大家可以学习下载 zookeeper下载地址:http://zookeeper.apache.org/releases.html kafka下载地址:http://kafka.apache.org/downloads.html 1、添加依赖 在 pom.xml 文件中添加kafka依赖&am…...

MOSFET
MOSFET 电子元器件百科 文章目录 MOSFET前言一、MOSFET是什么二、MOSFET类别三、MOSFET应用实例四、MOSFET作用原理总结前言 MOSFET是一种常见的半导体器件,通过栅极电场控制通道区的导通特性,以控制电流流动。它在现代电子电路中发挥着重要的作用,并广泛应用于各种应用领域…...

DriveWorks——参数化设计非标定制利器
DriveWorks基本介绍 DriveWorks是一套被 SOLIDWORKS 认可为金牌合作伙伴产品的设计自动化软件。DriveWorks 可自动创建特定于订单的销售文档和 SOLIDWORKS 制造数据。减少重复性任务,消除错误,增加销售额,并在创纪录的时间内交付定制产品。 为…...

DevEco Studio集成ArkUI-X
语雀知识库地址:语雀HarmonyOS知识库 飞书知识库地址:飞书HarmonyOS知识库 在上篇文章(HarmonyOS应用开发工具DevEco Studio安装与使用)中我说到官方推出了4.0 Beta版本的IDE,这篇文章就来介绍这个版本的安装与使用 该版本集成了HarmonyOS多…...

网络视频服务器的作用是什么?
随着互联网的快速发展和网络带宽的提升,网络视频已经成为人们日常生活中不可或缺的一部分。网络视频服务器作为支持和传输网络视频的关键基础设施,发挥着重要的作用。本文将以网络视频服务器的作用为方向,探讨其在现代社会中的重要性。 首先…...

解决vue3使用iconpark控制台预警提示问题
前言 最近在项目中使用 iconpark-icon 来管理图标,一切都很顺利,引入链接后,图标正常显示,没有报错。但是控制台却发出了预警信息。 [Vue warn]: Failed to resolve component: iconpark-icon If this is a native custom eleme…...

VMware 虚拟机 NAT 模式网络配置
配置的核心点在于 网关要一致,才能访问外网 比如下面的网关都是:192.168.145.2 问题总结: 当时重启电脑后如果连不上外网了,检查下 windows 服务中 NAT服务是否已经启动...

5-redis高级-哨兵
1 哨兵 1.1 python 操作哨兵 1 哨兵 # 主从---》一主多从-主库用来写-从库用来读-主库挂了--》整个系统就不能写数据了#主从复制存在的问题:1 主从复制,主节点发生故障,需要做故障转移,可以手动转移:让其中一个slave变…...

鸿蒙HarmonyOS4.0开发应用学习笔记
黑马程序员鸿蒙4.0视频学习笔记,供自己回顾使用。1.安装开发工具DevEco Studio 鸿蒙harmony开发文档指南 DevEco Studio下载地址 选择或者安装环境 选择和下载SDK 安装总览 编辑器界面 2.TypeScript语法 2.1变量声明 //string 、number、boolean、any、u…...

联通宽带+老毛子Padavan固件 开启IP v6
联通宽带开启IP v6 参考: 联通宽带开启 IPV6 的方法_联通ipv6怎么开通-CSDN博客 个人宽带如何开启IPv6网络访问 - 知乎 (zhihu.com) 首先,你要确定当前你所在的地区运营商已经开通了IPV6,可以使用手机流量 IP查询(ipw.cn) | IPv6测试 | IPv…...

唯创知音WT2003Hx系列单片机语音芯片:家庭理疗产品的智能声音伴侣
随着科技的不断创新,家庭理疗产品正迎来一场智能化的变革。唯创知音的WT2003Hx系列单片机语音芯片以其强大的功能和高品质音频播放能力,为家庭理疗产品带来了更为智能、沉浸式的用户体验。 1. MP3高品质音频播放 WT2003Hx系列语音芯片支持高品质的MP3音…...

2023_Spark_实验二十七:Linux中Crontab(定时任务)命令详解及使用教程
Crontab介绍: Linux crontab是用来crontab命令常见于Unix和类Unix的操作系统之中,用于设置周期性被执行的指令。该命令从标准输入设备读取指令,并将其存放于“crontab”文件中,以供之后读取和执行。该词来源于希腊语 chronos(χρ…...

Java动态代理实现与原理详细分析
Java动态代理实现与原理详细分析 关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式–代理模式,而对于代理,根据创建代理类的 时间点,又可以分为静态代理和动态代理。 1、代理模式 代理模式是常用的java设计模式&…...

[实践总结] 使用Apache HttpClient 4.x进行进行一次Http请求
使用Apache HttpClient 4.x进行进行一次Http请求 依赖 <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient --> <dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactI…...

易宝OA 两处任意文件上传漏洞复现
0x01 产品简介 易宝OA系统是一种专门为企业和机构的日常办公工作提供服务的综合性软件平台,具有信息管理、 流程管理 、知识管理(档案和业务管理)、协同办公等多种功能。 0x02 漏洞概述 易宝OA系统UploadFile、BasicService.asmx等接口处存在文件上传漏洞,未授权的攻击者可…...

echart饼图高亮颜色设置,数据为0时候,labelLine不显示
鼠标移上去高亮,颜色变浅,希望不改变颜色 在series.data中为各项设置itemStyle,官方设置不生效,不知原因,可能版本问题 itemStyle: {normal: { color: #DFEAFF, },emphasis: { color: #DFEAFF }},数据为0时候显示饼图…...

Kafka 的消息格式:了解消息结构与序列化
Kafka 作为一款高性能的消息中间件系统,其消息格式对于消息的生产、传输和消费起着至关重要的作用。本篇博客将深入讨论 Kafka 的消息格式,包括消息的结构、序列化与反序列化,以及一些常用的消息格式选项。通过更丰富的示例代码和深入的解析&…...

装箱 Box 数据类型
装箱是最简单直接的一种智能指针,它的类型是Box<T>。装箱使我们可以把数据存储到堆上,并在栈上保留一个指向堆数据的指针。装箱操作常常被用于下面的场景: 当你拥有一个无法在编译时确定大小的类型,但又想使用这个类型的值…...