环形缓冲区的实现原理(ring buffer)

2023-05-16

消息队列锁调用太频繁的问题算是解决了,另一个让人有些苦恼的大概是这太多的内存分配和释放操作了。频繁的内存分配不但增加了系统开销,更使得内存碎片不断增多,非常不利于我们的服务器长期稳定运行。也许我们可以使用内存池,比如SGI STL中附带的小内存分配器。但是对于这种按照严格的先进先出顺序处理的,块大小并不算小的,而且块大小也并不统一的内存分配情况来说,更多使用的是一种叫做环形缓冲区的方案,mangos的网络代码中也有这么一个东西,其原理也是比较简单的。

  就好比两个人围着一张圆形的桌子在追逐,跑的人被网络IO线程所控制,当写入数据时,这个人就往前跑;追的人就是逻辑线程,会一直往前追直到追上跑的人。如果追上了怎么办?那就是没有数据可读了,先等会儿呗,等跑的人向前跑几步了再追,总不能让游戏没得玩了吧。那要是追的人跑的太慢,跑的人转了一圈过来反追上追的人了呢?那您也先歇会儿吧。要是一直这么反着追,估计您就只能换一个跑的更快的追逐者了,要不这游戏还真没法玩下去。

  前面我们特别强调了,按照严格的先进先出顺序进行处理,这是环形缓冲区的使用必须遵守的一项要求。也就是,大家都得遵守规定,追的人不能从桌子上跨过去,跑的人当然也不允许反过来跑。至于为什么,不需要多做解释了吧。

  环形缓冲区是一项很好的技术,不用频繁的分配内存,而且在大多数情况下,内存的反复使用也使得我们能用更少的内存块做更多的事。

  在网络IO线程中,我们会为每一个连接都准备一个环形缓冲区,用于临时存放接收到的数据,以应付半包及粘包的情况。在解包及解密完成后,我们会将这个数据包复制到逻辑线程消息队列中,如果我们只使用一个队列,那这里也将会是个环形缓冲区,IO线程往里写,逻辑线程在后面读,互相追逐。可要是我们使用了前面介绍的优化方案后,可能这里便不再需要环形缓冲区了,至少我们并不再需要他们是环形的了。因为我们对同一个队列不再会出现同时读和写的情况,每个队列在写满后交给逻辑线程去读,逻辑线程读完后清空队列再交给IO线程去写,一段固定大小的缓冲区即可。没关系,这么好的技术,在别的地方一定也会用到的。



在通信程序中,经常使用环形缓冲区作为数据结构来存放通信中发送和接收的数据。环形缓冲区是一个先进先出的循环缓冲区,可以向通信程序提供对缓冲区的互斥访问。

1、环形缓冲区的实现原理

环形缓冲区通常有一个读指针和一个写指针。读指针指向环形缓冲区中可读的数据,写指针指向环形缓冲区中可写的缓冲区。通过移动读指针和写指针就可以实现缓冲区的数据读取和写入。在通常情况下,环形缓冲区的读用户仅仅会影响读指针,而写用户仅仅会影响写指针。如果仅仅有一个读用户和一个写用户,那么不需要添加互斥保护机制就可以保证数据的正确性。如果有多个读写用户访问环形缓冲区,那么必须添加互斥保护机制来确保多个用户互斥访问环形缓冲区。

图1、图2和图3是一个环形缓冲区的运行示意图。图1是环形缓冲区的初始状态,可以看到读指针和写指针都指向第一个缓冲区处;图2是向环形缓冲区中添加了一个数据后的情况,可以看到写指针已经移动到数据块2的位置,而读指针没有移动;图3是环形缓冲区进行了读取和添加后的状态,可以看到环形缓冲区中已经添加了两个数据,已经读取了一个数据。

个数据。

2、实例:环形缓冲区的实现

环形缓冲区是数据通信程序中使用最为广泛的数据结构之一,下面的代码,实现了一个环形缓冲区:

/*ringbuf .c*/

#include<stdio. h>

    #include<ctype. h>

#define NMAX 8

int iput = 0; /* 环形缓冲区的当前放入位置 */

int iget = 0; /* 缓冲区的当前取出位置 */

int n = 0; /* 环形缓冲区中的元素总数量 */

double buffer[NMAX];

/* 环形缓冲区的地址编号计算函数,如果到达唤醒缓冲区的尾部,将绕回到头部。

环形缓冲区的有效地址编号为:0到(NMAX-1)

*/

int addring (int i)

{

        return (i+1) == NMAX ? 0 : i+1;

}

/* 从环形缓冲区中取一个元素 */

double get(void)

{

int pos;

if (n>0){

                      Pos = iget;

                      iget = addring(iget);

                      n--;

                      return buffer[pos];

}

else {

printf(“Buffer is empty\n”);

return 0.0;

}

/* 向环形缓冲区中放入一个元素*/

void put(double z)

{

if (n<NMAX){

                      buffer[iput]=z;

                      iput = addring(iput);

                      n++;

}

else

printf(“Buffer is full\n”);

}

int main{void)

{

chat opera[5];

double z;

do {

printf(“Please input p|g|e?”);

scanf(“%s”, &opera);

               switch(tolower(opera[0])){

               case ‘p’: /* put */

                  printf(“Please input a float number?”);

                  scanf(“%lf”, &z);

                  put(z);

                  break;

case ‘g’: /* get */

                  z = get();

printf(“%8.2f from Buffer\n”, z);

break;

case ‘e’:

                  printf(“End\n”);

                  break;

default:

                  printf(“%s - Operation command error! \n”, opera);

}/* end switch */

}while(opera[0] != ’e’);

return 0;

}

在CAN通信卡设备驱动程序中,为了增强CAN通信卡的通信能力、提高通信效率,根据CAN的特点,使用两级缓冲区结构,即直接面向CAN通信卡的收发缓 冲区和直接面向系统调用的接收帧缓冲区。 通讯中的收发缓冲区一般采用环形队列(或称为FIFO队列),使用环形的缓冲区可以使得读写并发执行,读进程和写进程可以采用“生产者和消费者”的模型来 访问缓冲区,从而方便了缓存的使用和管理。然而,环形缓冲区的执行效率并不高,每读一个字节之前,需要判断缓冲区是否为空,并且移动尾指针时需要进行“折行处理”(即当指针指到缓冲区内存的末尾时,需要新将其定向到缓冲区的首地址);每写一个字节之前,需要判断缓区是否为,并且移动尾指针时同样需要进行“ 折行处理”。程序大部分的执行过程都是在处理个别极端的情况。只有小部分在进行实际有效的操作。这就是软件工程中所谓的“8比2”关系。结合CAN通讯实际情况,在本设计中对环形队列进行了改进,可以较大地提高数据的收发效率。 由于CAN通信卡上接收和发送缓冲器每次只接收一帧CAN数据,而且根据CAN的通讯协议,CAN控制器的发送数据由1个字节的标识符、一个字节的RTR 和DLC位及8个字节的数据区组成,共10个字节;接收缓冲器与之类似,也有10个字节的寄存器。所以CAN控制器收的数据是短小的定长帧(数据可以不满 8字节)。 于是,采用度为10字节的数据块业分配内存比较方便,即每次需要内存缓冲区时,直接分配10个字节,由于这10个字节的地址是线性的,故不需要进行“折行”处理。更重要的是,在向缓冲区中写数据时,只需要判断一次是否有空闲块并获取其块首指针就可以了,从而减少了重复性的条件判断,大大提高了程序的执行效率;同样在从缓冲队列中读取数据时,也是一次读取10字节的数据块,同样减少了重复性的条件判断。 在CAN卡驱动程序中采用如下所示的称为“Block_Ring_t”的数据结构作为收发数据的缓冲区:

typedef struct {

long signature;

unsigned char *head_p;

unsigned char *tail_p;

unsigned char *begin_p;

unsigned char *end_p;

unsigned char buffer [BLOCK_RING_BUFFER_SIZE];

int usedbytes;

}Block_Ring_t;

该数据结构在通用的环形队列上增加了一个数据成员usedbytes,它表示当前缓冲区中有多少字节的空间被占用了。使用usedbytes,可以比较方 便地进行缓冲区满或空的判断。当usedbytes=0时,缓冲区空;当usedbytes=BLOCK_RING_BUFFER_SIZE时,缓冲区 满。 本驱动程序除了收发缓冲区外,还有一个接收帧缓冲区,接收帧队列负责管理经Hilon A协议解包后得到的数据帧。由于有可能要同接收多个数据帧,而根据CAN总线遥通信协议,高优先级的报文将抢占总线,则有可能在接收一个低优先级且被分为 好几段发送的数据帧时,被一个优先级高的数据帧打断。这样会出现同时接收到多个数据帧中的数据包,因而需要有个接收队列对同时接收的数据帧进行管理。 当有新的数据包到来时,应根据addr(通讯地址),mode(通讯方式),index(数据包的序号)来判断是否是新的数据帧。如果是,则开辟新的 frame_node;否则如果已有相应的帧节点存地,则将数据附加到该帧的末尾;在插入数据的同时,应该检查接收包的序号是否正确,如不正确将丢弃这包 数据。 每次建立新的frame_node时,需要向frame_queue申请内存空间;当frame_queue已满时,释放掉队首的节点(最早接收的但未完 成的帧)并返回该节点的指针。 当系统调用读取了接收帧后,释放该节点空间,使设备驱动程序可以重新使用该节点。

形缓冲区:环形缓冲队列学习

来源: 发布时间:星期四, 2008年9月25日 浏览:117次 评论:0

项目中需要线程之间共享一个缓冲FIFO队列,一个线程往队列中添数据,另一个线程取数据(经典的生产者-消费者问题)。开始考虑用STL的vector 容器, 但不需要随机访问,频繁的删除最前的元素引起内存移动,降低了效率。使用LinkList做队列的话,也需要频繁分配和释放结点内存。于是自己实现一个有 限大小的FIFO队列,直接采用数组进行环形读取。

队列的读写需要在外部进程线程同步(另外写了一个RWGuard类, 见另一文)

到项目的针对性简单性,实现了一个简单的环形缓冲队列,比STL的vector简单

PS: 第一次使用模板,原来类模板的定义要放在.h 文件中, 不然会出现连接错误。

template <class _Type>
class CShareQueue 
{
public:
CShareQueue();
CShareQueue(unsigned int bufsize);
virtual ~CShareQueue();

_Type pop_front();
bool push_back( _Type item);
//返回容量
unsigned int capacity() { //warning:需要外部数据一致性
return m_capacity;
}
//返回当前个数
unsigned int size() { //warning:需要外部数据一致性
return m_size;
}
//是否满//warning: 需要外部控制数据一致性
bool IsFull() {
return (m_size >= m_capacity);
}

bool IsEmpty() {
return (m_size == 0);
}


protected:
UINT m_head;
UINT m_tail;
UINT m_size;
UINT m_capacity;
_Type *pBuf;


};

template <class _Type>
CShareQueue<_Type>::CShareQueue() : m_head(0), m_tail(0), m_size(0)
{
pBuf = new _Type[512];//默认512
m_capacity = 512;
}

template <class _Type>
CShareQueue<_Type>::CShareQueue(unsigned int bufsize) : m_head(0), m_tail(0)
{
if( bufsize > 512 || bufsize < 1)
{
pBuf = new _Type[512];
m_capacity = 512;
}
else
{
pBuf = new _Type[bufsize];
m_capacity = bufsize;
}
}

template <class _Type>
CShareQueue<_Type>::~CShareQueue()
{
delete[] pBuf;
pBuf = NULL;
m_head = m_tail = m_size = m_capacity = 0;
}

//前面弹出一个元素
template <class _Type>
_Type CShareQueue<_Type>::pop_front()
{
if( IsEmpty() )
{
return NULL;
}
_Type itemtmp;
itemtmp = pBuf[m_head];
m_head = (m_head + 1) % m_capacity;
--m_size;
return itemtmp;

}

//从尾部加入队列
template <class _Type>
bool CShareQueue<_Type>::push_back( _Type item)
{
if ( IsFull() )
{
return FALSE;
}
pBuf[m_tail] = item;
m_tail = (m_tail + 1) % m_capacity;
++m_size;
return TRUE;
}


#endif



http://hi.baidu.com/zkheartboy/blog/item/f162b20fdbf250eeab6457be.html

实现环形缓冲区的通用类: http://hi.baidu.com/broland/blog/item/6a6ddf813f3425c69123d956.html

http://hi.baidu.com/uc100200/blog/item/c6d670543df4544fd00906ac.html

http://hi.baidu.com/282280072/blog/item/9927685090cbb9928d543075.html




环形缓冲区介绍 

环形缓冲区是生产者和消费者模型中常用的数据结构。生产者将数据放入数组的尾端,而消费者从数组的另一端移走数据,当达到数组的尾部时,生产者绕回到数组的头部。

  如果只有一个生产者和一个消费者,那么就可以做到免锁访问环形缓冲区(Ring Buffer)。写入索引只允许生产者访问并修改,只要写入者在更新索引之前将新的值保存到缓冲区中,则读者将始终看到一致的数据结构。同理,读取索引也只允许消费者访问并修改。

环形缓冲区实现原理图


如图所示,当读者和写者指针相等时,表明缓冲区是空的,而只要写入指针在读取指针后面时,表明缓冲区已满。


环形缓冲区内部结构
  ◇外部接口相似
  在介绍环形缓冲区之前,咱们先来回顾一下普通的队列。普通的队列有一个写入端和一个读出端。队列为空的时候,读出端无法读取数据;当队列满(达到最大尺寸)时,写入端无法写入数据。
  对于使用者来讲,环形缓冲区和队列缓冲区是一样的。它也有一个写入端(用于push)和一个读出端(用于pop),也有缓冲区“满”和“空”的状态。所以,从队列缓冲区切换到环形缓冲区,对于使用者来说能比较平滑地过渡。
  ◇内部结构迥异
  虽然两者的对外接口差不多,但是内部结构和运作机制有很大差别。队列的内部结构此处就不多啰嗦了。重点介绍一下环形缓冲区的内部结构。
  大伙儿可以把环形缓冲区的读出端(以下简称R)和写入端(以下简称W)想象成是两个人在体育场跑道上追逐(R追W)。当R追上W的时候,就是缓冲区为空;当W追上R的时候(W比R多跑一圈),就是缓冲区满。
  为了形象起见,去找来一张图并略作修改,如下:


  从上图可以看出,环形缓冲区所有的push和pop操作都是在一个固定 的存储空间内进行。而队列缓冲区在push的时候,可能会分配存储空间用于存储新元素;在pop时,可能会释放废弃元素的存储空间。所以环形方式相比队列方式,少掉了对于缓冲区元素所用存储空间的分配、释放。这是环形缓冲区的一个主要优势。

  ★环形缓冲区的实现 
  如果你手头已经有现成的环形缓冲区可供使用,并且你对环形缓冲区的内部实现不感兴趣,可以跳过这段。
  ◇数组方式 vs 链表方式
  环形缓冲区的内部实现,即可基于数组(此处的数组,泛指连续存储空间)实现,也可基于链表实现。
  数组在物理存储上是一维的连续线性结构,可以在初始化时,把存储空间一次性 分配好,这是数组方式的优点。但是要使用数组来模拟环,你必须在逻辑上把数组的头和尾相连。在顺序遍历数组时,对尾部元素(最后一个元素)要作一下特殊处理。访问尾部元素的下一个元素时,要重新回到头部元素(第0个元素)。如下图所示:


  使用链表的方式,正好和数组相反。链表省去了头尾相连的特殊处理。但是链表在初始化的时候比较繁琐,而且在有些场合(比如后面提到的跨进程的IPC)不太方便使用。
  ◇读写操作
  环形缓冲区要维护两个索引,分别对应写入端(W)和读取端(R)。写入(push)的时候,先确保环没满,然后把数据复制到W所对应的元素,最后W指向下一个元素;读取(pop)的时候,先确保环没空,然后返回R对应的元素,最后R指向下一个元素。
  ◇判断“空”和“满”
  上述的操作并不复杂,不过有一个小小的麻烦:空环和满环的时候,R和W都指向同一个位置!这样就无法判断到底是“空”还是“满”。大体上有两种方法可以解决该问题。
  办法1:始终保持一个元素不用
  当空环的时候,R和W重叠。当W比R跑得快,追到距离R还有一个元素间隔的时候,就认为环已经满。当环内元素占用的存储空间较大的时候,这种办法显得很土(浪费空间)。
  办法2:维护额外变量
  如果不喜欢上述办法,还可以采用额外的变量来解决。比如可以用一个整数记录当前环中已经保存的元素个数(该整数>=0)。当R和W重叠的时候,通过该变量就可以知道是“空”还是“满”。
  ◇元素的存储
  由于环形缓冲区本身就是要降低存储空间分配的开销,因此缓冲区中元素的类型要选好。尽量存储 类型的数据,而不要存储指针(引用) 类型的数据。因为指针类型的数据又会引起存储空间(比如堆内存)的分配和释放,使得环形缓冲区的效果打折扣。

  ★应用场合 
  刚才介绍了环形缓冲区内部的实现机制。按照前一个帖子 的惯例,我们来介绍一下在线程和进程方式下的使用。
  如果你所使用的编程语言和开发库中带有现成的、成熟的 环形缓冲区,强烈建议使用现成的库,不要重新制造轮子;确实找不到现成的,才考虑自己实现。如果你纯粹是业余时间练练手,那另当别论。
  ◇用于并发线程
  和线程中的队列缓冲区类似,线程中的环形缓冲区也要考虑线程安全的问题。除非你使用的环形缓冲区的库已经帮你实现了线程安全,否则你还是得自己动手搞定。线程方式下的环形缓冲区用得比较多,相关的网上资料也多,下面就大致介绍几个。
  对于C++的程序员,强烈推荐使用boost 提供的circular_buffer 模板,该模板最开始是在boost 1.35版本中引入的。鉴于boost在C++社区中的地位,大伙儿应该可以放心使用该模板。
  对于C程序员,可以去看看开源项目circbuf ,不过该项目是GPL协议的,不太爽;而且活跃度不太高;而且只有一个开发人员。大伙儿慎用!建议只拿它当参考。
  对于C#程序员,可以参考CodeProject上的一个示例 。
  ◇用于并发进程
  进程间的环形缓冲区,似乎少有现成的库可用。大伙儿只好自己动手、丰衣足食了。
  适用于进程间环形缓冲的IPC类型,常见的有共享内存 和文件。在这两种方式上进行环形缓冲,通常都采用数组的方式实现。程序事先分配好一个固定长度的存储空间,然后具体的读写操作、判断“空”和“满”、元素存储等细节就可参照前面所说的来进行。
  共享内存方式的性能很好,适用于数据流量很大的场景。但是有些语言(比如Java)对于共享内存不支持。因此,该方式在多语言协同开发的系统中,会有一定的局限性。
  而文件方式在编程语言方面支持很好,几乎所有编程语言都支持操作文件。但它可能会受限于磁盘读写(Disk I/O)的性能。所以文件方式不太适合于快速数据传输;但是对于某些“数据单元 ”很大的场合,文件方式是值得考虑的。
  对于进程间的环形缓冲区,同样要考虑好进程间的同步、互斥等问题。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

环形缓冲区的实现原理(ring buffer) 的相关文章

  • 震惊!Selenium分手PhantomJS

    背景 今天本地调试基于Selenium 43 PhantomJS的动态爬虫程序顺利结束后 xff0c 着手部署到服务器上 xff0c 刚买的热乎的京东云 xff0c 噼里啪啦一顿安装环境 xff0c 最后跑的时候报了这么个错误 xff1a
  • Android Studio flutter关于GradleException和NonNull报错的问题

    Android Studio flutter关于GradleException和NonNull报错的问题 问题描述build gradle的报错NonNull的报错 问题追踪及尝试解决解决方案 方案一 暴力解决 方案二 优雅忽略 方案三 心
  • gcc-multilib在Ubuntu20.04上无法安装

    2021SC 64 SDUSC Ubuntu20 04无法安装 gcc multilib g 43 43 multilib 错误内容解决方案 错误内容 执行sudo apt install gcc multilib g 43 43 mult
  • docker 常用命令总结

    1 docker login docker login OPTIONS SERVER SERVER 远程仓库地址 OPTIONS 的常用值 u string 用户名 p string 密码 2 docker search docker se
  • vscode提取拓展时出错。XHR failed

    问题描述 使用vscode的拓展搜索时出现报错 xff0c 如下图 xff1a 问题分析 使用cmd的ping工具尝试ping域名 marketplace visualstudio com 无法ping通 解决方案 1 打开本地配置文件 C
  • MAC下常用命令的中文帮助文档(man)

    默认在终端进行man命令 xff0c 如 xff1a man ls xff0c 会显示英文的帮助文档 本文教你如何查看中文文档 资源 xff1a 1 manpages zh 1 5 2 tar bz2 2 groff 1 21 tar gz
  • Float数值表示

    float浮点用32个二进制位表示 第1位S代表正负号 0为正数 1为负数 第2 9位E是阶码 代表2的指数次方 指数 61 阶码 127 第10 32位代表尾数1 M 阶码取值范围在1 254时 f 61 1 S 1 M 2 E 127
  • python是什么意思

    python本意是 xff1a 巨蛇 xff0c 大蟒 xff1b Python是一种跨平台的计算机程序设计语言 python是一个高层次的结合了解释性 编译性 互动性和面向对象的脚本语言 最初被设计用于编写自动化脚本 shell xff0
  • 通过iptables 禁止访问域名方法整合

    更新2 新方法 xff1a 由于使用ipset来禁域名 xff0c 老是会误ban xff0c 这里想到了一个新方法 iptables t nat A PREROUTING p udp dport 53 j DNAT to 本机dns ip
  • 将最优装载问题的贪心算法推广到2艘船的情形,贪心算法仍能产生最优解吗?

    算法分析第五次讨论马上就要到了 xff0c 我搜索了一下讨论的第一道题目 xff0c 发现竟然没有详细的解释 xff0c 没有办法只能自己写了 翻了一下习题解答 xff0c 它说见主教材第5章的装载问题 第五章就讲了两艘船的装载问题 xff
  • 三种常用的数据库模型的优缺点(课后习题)

    12 试述网状 层次 xff0c 关系数据库的优缺点 网状数据库 xff1a 优点 xff1a 能够更为直接地描述现实世界 xff0c 如一个节点可以有多个双亲 xff0c 节点之间可以有多种联系 具有良好的性能 xff0c 存取效率较高
  • Pycharm连接GitHub出错

    最近才得知GitHub的妙用 xff0c 不会GitHub的程序员只是单纯的代码搬运工 在使用的过程中 xff0c 得知Pycharm原来可以直接连接GitHub xff0c 再开发Python项目的时候 xff0c 能省去不少的麻烦 但第
  • 如何把本地的Django项目部署到服务器(亲测)

    如何将本地的Django项目部署到云服务器 项目代码见GitHub 博客网址 开发环境 开发语言 xff1a Python后台框架 xff1a Django前端框架 xff1a bootstrapweb服务器 xff1a nginxwsgi
  • 如何解决IDEA或PyCharm 莫名出现的黑色斑块,或者说文字下方出现随鼠标移动的黑色底色

    如下图所示 xff0c idea在使用的时候 xff0c 经常会出现大块的黑色 xff0c 而且是偶然的 xff0c 无法自己重现这个bug 这是什么莫名其妙的bug xff1f 经常会不定时地出现 xff0c 有没有人能解释一下 每次都要
  • 前端FISH框架学习笔记

    Fish 0 学习路线 前期自学 fish基础组件 xff08 写简单demo xff09 gt 模块化开发 xff08 写简单demo xff09 gt 实际项目代码阅读 实际开发 看组件示例 看fish API 看代码示例 百度 1 环
  • shell脚本自动部署Springboot项目到云服务器

    如何用shell脚本自动部署Springboot项目 在开发Springboot项目时 xff0c 我们可能需要经常更新服务器上的代码 xff0c 并把项目部署在服务器上 xff0c 而每次都需要输入一连串的命令 xff0c 这样效率实在不
  • lubuntu操作及桌面配置(1)

    lubuntu操作及桌面配置 xff08 1 xff09 1 桌面环境 xff1a LXDE 特点 xff1a LXDE的资源占用更小 xff0c 适合在配置比较低的电脑上工作 它有很多特点 xff0c 如程序间无相依性 2 LXDE桌面环
  • 不可思议的OOM

    作者 xff1a 陶菜菜 链接 xff1a http www jianshu com p e574f0ffdb42 來源 xff1a 简书 著作权归作者所有 商业转载请联系作者获得授权 xff0c 非商业转载请注明出处 摘要 本文发现了一类
  • Linux防火墙firewalld不生效,无法拦截Docker映射端口

    今天出现了一个奇怪的现象 xff0c centos服务器上的防火墙 firewall 没有开放8103端口 xff0c 但是依然可以访问 服务器开放的端口如下 xff1a 可以看出并没有开放8103端口 开放的服务如下 xff1a 也没有开
  • java各种集合类区别

    最近面试经常遇到java集合类的问题 xff0c 上网搜了一下 xff0c 做个笔记 百度的图 集合类 型主要有3种 xff1a set 集 xff09 list 列表 xff09 和map 映射 集合接口 分为 xff1a Collect

随机推荐

  • windows10下wsl2、Ubuntu20.04、中文设置、Rust、vscode、chrome谷歌浏览器安装配置总结

    1 Microsoft Store 中安装 windows Terminal 2 更新 wsl 或 Microsoft Store 中安装 wsl2 wsl span class token parameter variable versi
  • 【python算法】图的遍历与最小路径

    数据结构中 xff0c 图的应用场景非常广泛 xff0c 与我们的生活息息相关 xff0c 在基于图做的应用中 xff0c 比较典型的有 xff1a 在交通规划中的最小生成树 xff0c 用于导航的最短路径等 比如下图 这里 xff0c 我
  • 安装react-devtools时npm install失败解决方法

    网上的所有教程基本都是把v3zip下载下来后淘宝镜像安装依赖 xff1a npm registry https registry npm taobao org install 但按照这种方法会出现如下报错 npm ERR code 1 np
  • java -虹软Caused by: java.lang.UnsatisfiedLinkError: Can‘t load library: **\WIN64\libarcsoft_face.dll

    错误详情 Caused by java lang UnsatisfiedLinkError Can t load library F code WIN64 libarcsoft face dll 如图 xff1a 错误原因 一般遇到问题 x
  • Fragment的使用(Android实现底部导航栏)

    xfeff xfeff xfeff xfeff 一 布局页面添加 1 添加四个切换页面的布局 xff08 1 xff09 四个切换页面的布局 四个页面相同 xff09 xff1a lt xml version 61 34 1 0 34 en
  • Java 线程安全

    引入1 xff1a 计算机内存模型 span class token number 1 span 因为向主内存中读写数据的速度要远远小于 span class token constant CPU span 处理数据的速度 xff0c 所有
  • Debian11安装MySql8

    下载地址点击这里 官方安装文档点击这里 Installing MySQL on Linux Using Debian Packages from Oracle xff09 安装 span class token comment 安装依赖 s
  • 消息队列技术的介绍和原理(MQ)

    最近要做一个项目准备用分布式消息队列 xff0c 花点时间看了下 消息队列技术是分布式应用间交换信息的一种技术 消息队列可驻留在内存或磁盘上 队列存储消息直到它们被应用程序读走 通过消息队列 xff0c 应用程序可独立地执行 它们不需要知道
  • win10如何修改C盘User下的用户名

    温馨提示 仅供参考 xff0c 不建议小白在本机测试 xff0c 不然会有需要 重装 的风险 建议操作前设置还原点 重要数据备份 xff01 xff01 xff01 然后Win11就别尝试了 xff0c 而且一旦失败的话 xff0c 就只能
  • 极狐Gitlab操作手册

    用户管理 普通用户可以访问他们的群组和项目 用户可以无限制地访问所有群组 项目 用户和功能 群组管理 项目管理 创建项目 为项目添加成员 其它设置 为当前用户配置SSH密钥 本地生成SSH密钥 提交本地项目到gitlab span clas
  • WIN11之RocketMQ5.0安装

    官网地址 xff1a https rocketmq apache org docs quick start 下载地址 xff1a https rocketmq apache org dowloading 下载 系统要求 span class
  • Kubernetes 对象

    什么是对象 K8s集群中创建的任何东西都可以被视为对象 xff1a Deployment Pod Service等等 对象类型 kubectl api resources span class token comment 查询所有type
  • K8S DashBoard控制台

    前言 Dashboard 是基于网页的 Kubernetes 用户界面 你可以使用 Dashboard 将容器应用部署到 Kubernetes 集群中 xff0c 也可以对容器应用排错 xff0c 还能管理集群资源 你可以使用 Dashbo
  • Debian11之基于二进制安装K8S(v1.26.x) 集群

    官网地址 xff1a https kubernetes io zh cn docs home supported doc versions 资源列表 主机IP主机名称主机角色软件192 168 111 30master1主节点1kube a
  • Kubernetes Service、Ingress、Ingress Controller

    Kubernetes 网络模型 K8S 是一种容器编排系统 xff0c 可以方便地管理和部署容器应用程序 它支持通过四层负载和七层负载向容器集群中的应用程序提供负载均衡 四层负载是一种基于传输层协议 xff08 例如TCP UDP xff0
  • 浅析JAVA中的抽象类

    span class hljs keyword abstract span class Animal span class hljs keyword abstract span span class hljs keyword void sp
  • 安装 Ubuntu

    1 del 进入bios 选择从USB启动 2 安装ubuntu 3 准备安装Ubuntu 不用选 4 安装类型 选择something else 可以自己分区 5 分为四个区 swap 交换分区 不用格式化 boot 引导和内核分区 格式
  • Linux安装libpcap(pcap.h库)(以Ubuntu 18.04为例)

    做毕业设计需要用到libpcap来抓包 借此次机会完整记录下自己的安装过程 xff0c 前人种树后人乘凉 到libpcap官网去下载最新的源码包 下载完成后tar xzf 文件 tar gz 解压 xff0c 于是我们可以看到完整的源码目录
  • rabbitmq的waitForConfirms和waitForConfirmsOrDie作用和区别

    rabbitmq的waitForConfirms和waitForConfirmsOrDie作用和区别 解决方法 xff1a 发布消息后通过执行channel waitForConfirmsOrDie xff08 long xff09 方法或
  • 环形缓冲区的实现原理(ring buffer)

    消息队列锁调用太频繁的问题算是解决了 xff0c 另一个让人有些苦恼的大概是这太多的内存分配和释放操作了 频繁的内存分配不但增加了系统开销 xff0c 更使得内存碎片不断增多 xff0c 非常不利于我们的服务器长期稳定运行 也许我们可以使用