商业网站开发模式/360搜图片识图
共享内存+消息队列+信号量
- 1.共享内存
- 1.1共享内存的原理
- 1.2共享内存的概念
- 1.3接口的认识
- 1.4实操
- comm.hpp
- service.cc (写)
- clint.cc (读)
- 1.5共享内存的总结
- 1.6共享内存的内核结构
- 2.消息队列
- 2.1原理
- 2.2接口
- 3.信号量
- 3.1信号量是什么
- 3.2为什么要信号量
- 3.3接口
- 4.IPC资源的组织方式
进程间通信方式目前我们已经学了匿名管道,命名管道。让两个独立的进程通信,前提是看到同一份资源。匿名管道适用于血缘关系的进程,一个打开写端一个打开读端实现的。命名管道适用于完全独立的进程,打开同一份文件实现的。
接下来我们看看剩下的实现进程间通信的方式。
1.共享内存
1.1共享内存的原理
可执行程序加载到内存,OS会对进程进行管理。进程的内核结构是独立的,加载到物理地址的地址也独立,因此进程具有独立性,互不影响。
那共享内存是如何实现两个独立的进程进行通信的呢?
1.申请一块空间(用户给OS发信号,然后OS去申请)
2.将创建好的内存经过页表映射到进程地址空间中的一段区域(将这块区域的起始地址返回给用户,用户通过访问这里的起始地址方式来进行对这块区域的访问)
3.未来不想通信了
a.取消进程和内存的映射关系
b.释放内存
上面就是共享内存的原理。
这块申请的内存—>共享内存
进程和内存建立映射关系过程—>进程和共享内存挂接
取消进程和内存的映射关系—>去关联
释放内存—>释放共享内存
如何理解上面这个过程?
在内存上申请空间,然后把地址返回,是不是像C/C++空间的申请,如malloc函数,底层都是一样的先去物理内存申请空间,然后经过页表映射到进程地址空间,最后把这块空间的起始地址返回用户。虽然过程都是一样,但是malloc申请的空间没有办法让另一个进程看见,因为这块空间是在堆上申请的,OS并没有专门为malloc这样的机制和其他进程建立映射关系策略。
a.进程间通信,是专门设计的,用来IPC
b.共享内存是一种通信方式,所有想通信的进程,都可以用
c.OS中一定可能会同时存在很多的共享内存
1.2共享内存的概念
通过让不同的进程,看到同一个内存的方式:共享内存。
1.3接口的认识
1.创建共享内存。
size 要申请多大的内存空间
shmflg 常用参数。
看到这里这个参数是不是和open接口有点类似,大写的宏。
shmflg是一个标志位。
IPC_CREAT:如果想创建的共享内存不存在,就创建,如果存在就获取
IPC_EXCL:无法单独使用。
IPC_CREAT | IPC_EXCL:如果不存在就创建,如果存在就出错返回。用户创建共享内存如果成功,一定是一个新的共享内存。
创建共享内存非常容易,那如果保证进程看到的是同一块共享内存呢?
key用来保证。
key是什么不重要,能进行唯一性标识最重要。
将路径名和项目标识符转换为key。
随便写个路径和项目id。经过算法转换成key。
两个进程传一样参数,能保证是同一个key,因此可以在系统中找到同一个内存。
返回值。成功是返回共享内存的标识符,失败返回-1。
再来理解key_t key
OS中一定可能会同时存在很多的共享内存。
OS也要对共享内存进行管理—>先描述,在组织。
申请一块空间—>共享内存=物理内存块+共享内存的相关属性
key是什么不重要,能进行唯一标识最重要。
创建共享内存的时候,key能保证共享内存在系统中的唯一性。两个进程如何看到同一份资源,只要另一个进程也看到同一个key。
key在那?
key在共享内存的相关属性这个结构体里。
创建共享内存把key传到shmget,本质上是把key设置进创建好的共享内存的某个属性里,另一个进程获取时,查这么多的共享内存,不是查共享内的物理内存块,而是去遍历共享内存对于的相关属性去查找key。
key传到shmget,设置到共享内存属性中,用来表示共享内存在内核中的唯一性。
返回值返回的共享内存的标识符取名shmid。
shmid vs key的关系
shmid是为了用户去访问共享内存的。就像fd vs inode的关系。
2.共享内存和进程关联
shmid:和哪一个共享内存关联
shmaddr:把共享内存映射到地址空间的那一块区域
shmflg:与读写权限有关,默认设置为0
成功是返回的是对应进程地址空间的起始地址,失败返回-1。
3.删除共享内存之前要先去关联
将共享内存从当前调用这个函数的进程地址空间进行卸装
shmaddr:进程地址空间的首地址
4.删除共享内存
删除共享内存接口是shmctl,本质上控制共享内存,不过常用的是删除选项。
shmid:控制哪一个共享内存
cmd:做什么控制,常用选项IPC_RMID
buf:如果不想获得共享内存的属性可以设置nullptr,不然就传一个对象接收共享内存部分属性信息。
1.4实操
comm.hpp
将写端和读端用的代码封装起来。
#include<iostream>
#include<cerrno>
#include<cstring>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>#define PATHNAME "."
#define PROJ_JD "0x11"#define MAX_SIZE 4096key_t GetKey()
{key_t k=ftok(PATHNAME,PROJ_JD);//获得唯一标识keyif(k < 0){//cin cout cerr->stdin stdout stderr(默认打开的三个文件)-(fd)>0,1,2->键盘,显示器,显示器cerr<<errno<<":"<<strerror(errno)<<endl;exit(1);}return k;
}//获得共享内存表示符shmid
int getShmHelper(int key,int shmflg)
{int shmid=shemget(key,MAX_SIZE,shmflg);if(shmid < 0){cerr<<errno<<":"<<strerror(errno)<<endl;exit(1);}return shmid;
}//写端创建共享内存
int CreateShm(key_t key)
{//这里运行时会报错。下面再看运行结果有解决方法return getShmHelper(key,IPC_CREAT|IPC_EXCL);
}//读端获取共享内存
int GetShm()
{return getShmHelper(key,IPC_CREAT);
}
看运行结果写端和读端的key是一样的,shmid也是一样的。
当我再次执行一样的操作,发现不能再创建共享内存了。显示已经存在了。可是我已经退出进程了啊。OS不会帮我自动关闭吗。
共享内存的生命周期是随操作系统的,不是随进程的
查看IPC资源
ipcs查看IPC资源
ipcs -m 查看共享内存
ipcs -q 查看队列
ipcs -s 查信号量
ipcrm -m shmid 删除共享内存
代码删除共享内存
//删除共享内存
void DelShm(int shmid)
{
//删除共享内存
void DelShm(int shmid)
{if(shmctl(shmid,IPC_RMID,nullptr) == -1){cerr<<errno<<":"<<strerror(errno)<<endl;}}
}
通信之前需要关联(挂接:将共享内存经页表映射到进程地址空间)
void* attachShm(int shimid)
{void* mem=shmat(shimid,nullptr,0);//linux 64位机器指针大小位9if((long long)men == -1L)//1L代表是长整型{cerr<<errno<<":"<<strerror(errno)<<endl;exit(1);}return men;
}
删除共享内存之前需要去关联
void detachShm(const void* adder)
{if(shmdt(adder) == -1){cerr<<errno<<":"<<strerror(errno)<<endl;exit(1);}
}
完整代码如下
#include<iostream>
#include<cerrno>
#include<cstring>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<unistd.h>using namespace std;#define PATHNAME "."
#define PROJ_JD 0x11#define MAX_SIZE 4096key_t GetKey()
{key_t k=ftok(PATHNAME,PROJ_JD);if(k < 0){//cin cout cerr->stdin stdout stderr(默认打开的三个文件)-(fd)>0,1,2->键盘,显示器,显示器cerr<<errno<<":"<<strerror(errno)<<endl;exit(1);}return k;
}//获得共享内存表示符shmid
int getShmHelper(int key,int flage)
{int shmid=shmget(key,MAX_SIZE,flage);if(shmid < 0){ cerr<<errno<<":"<<strerror(errno)<<endl;exit(1);}return shmid;
}//写端创建共享内存
int CreateShm(key_t key)
{//这里运行时会报错。下面再看运行结果有解决方法return getShmHelper(key,IPC_CREAT|IPC_EXCL);
}//读端获取共享内存
int GetShm(key_t key)
{return getShmHelper(key,IPC_CREAT);
}//关联
void* attachShm(int shimid)
{void* mem=shmat(shimid,nullptr,0);//linux 64位机器指针大小位9if((long long)mem == -1L)//1L代表是长整型{cerr<<errno<<":"<<strerror(errno)<<endl;exit(1);}return mem;
}//去关联
void detachShm(const void* adder)
{if(shmdt(adder) == -1){cerr<<errno<<":"<<strerror(errno)<<endl;exit(1);}
}//删除共享内存
void DelShm(int shmid)
{if(shmctl(shmid,IPC_RMID,nullptr) == -1){cerr<<errno<<":"<<strerror(errno)<<endl;}}
service.cc (写)
#include"comm.hpp"int main()
{key_t key=GetKey();printf("key->%d\n",key);int shmid=CreateShm(key);printf("shimid->%d\n",shmid);//关联char*start=(char*)attachShm(shmid);//我想将这个地址认为是一字符串;printf("attach success, address start: %p\n", start);//写while(true){}//删除DelShm(shmid);return 0;
}
共享内存没有read和write这样的接口。
写—>直接把内容写到这块内存
读—>直接打印这块内存
以往我们可能是这样的写法,对于往内存中写有点麻烦了。
//写char buffer[1024];const char* messge="hello clint,我是另一个进程,我正在和你通信";int id=getpid();int cnt=0;while(true){//以往我们的做法snprintf(buffer,sizeof buffer,"%s([%d]->[%d])",messge,cnt++,id);memcpy(start,buffer,strlen(buffer)+1);}
看这个函数,我们可以直接把内容写到内存。
完整代码如下
#include"comm.hpp"int main()
{key_t key=GetKey();printf("key->%d\n",key);int shmid=CreateShm(key);printf("shimid->%d\n",shmid);//关联char* start=(char*)attachShm(shmid);//我想将这个地址认为是一字符串;printf("attach success, address start: %p\n", start);//写char buffer[1024];const char* messge="hello clint,我是另一个进程,我正在和你通信";int id=getpid();int cnt=0;while(true){snprintf(start,MAX_SIZE,"%s([%d]->[%d])",messge,cnt++,id);//以往我们的做法// snprintf(buffer,sizeof buffer,"%s([%d]->[%d])",messge,cnt++,id));// memcpy(start,buffer,strlen(buffer)+1);}//去关联detachShm(start);//删除DelShm(shmid);return 0;
}
clint.cc (读)
#include"comm.hpp"int main()
{key_t key=GetKey();printf("key->%d\n",key);int shmid=GetShm(key);printf("shimid->%d\n",shmid);char* start=(char*)attachShm(shmid);printf("attach success, address start: %p\n", start);while(true){printf("service say : %s\n", start);}return 0;
}
运行时报了这个没有权限的错误。
这是因为再创建共享内存的时候没有给权限。
补上权限即可
看运行结果,虽然两个进程进行了通信,但是这个通信有点问题。
共享内存不像管道那样,阻塞等待,而是一直在读。
1.5共享内存的总结
共享内存的特点:
1.共享内存的生命周期是随OS的,不是随进程的。
2.所有进程间通信速度最快的(能大大的减少数据的拷贝次数)—>优点。
同样的代码,如果用管道来实现,综合考虑管道和共享内存,考虑键盘输入和显示器输出,共享内存有几次数据拷贝?管道呢?
3.不给我进行同步和互斥的操作,没有对数据做任何保护---->缺点
1.6共享内存的内核结构
给这个接口传一个struct shmid_de 对象,就看到共享内存一些信息。
#include"comm.hpp"int main()
{key_t key=GetKey();printf("key->%d\n",key);int shmid=GetShm(key);printf("shimid->%d\n",shmid);char* start=(char*)attachShm(shmid);printf("attach success, address start: %p\n", start);while(true){printf("service say : %s\n", start);struct shmid_ds ds;shmctl(shmid,IPC_STAT,&ds);printf("获得属性: size :%d,link :%d\n",ds.shm_segsz,ds.shm_nattch);sleep(1);}return 0;
}
我们确实获得了共享内核的一些属性。
我们的key在struct shmid_ds结构体的第一个变量里。
#include"comm.hpp"int main()
{key_t key=GetKey();printf("key->%d\n",key);int shmid=GetShm(key);printf("shimid->%d\n",shmid);char* start=(char*)attachShm(shmid);printf("attach success, address start: %p\n", start);while(true){printf("service say : %s\n", start);struct shmid_ds ds;shmctl(shmid,IPC_STAT,&ds);printf("获得属性: size :%d,link :%d,key :%d\n",\ds.shm_segsz,ds.shm_nattch,ds.shm_perm.__key);sleep(1);}return 0;
}
共享内存大小一般建议4KB(4096)的整数倍
系统分配共享内存是以4KB为单倍的!------内存划分内存块的基本单位page
虽然申请大小是4097,但是内核给你的实际是40962,内核给你向上取整。
虽然内核给的是40962,但是注意内核给你的,和你能用的是两码事。
2.消息队列
在前面说过System V IPC—>聚焦在本地通信,目前已经陈旧了,共享内存还是值得我们好好学习一番,剩下的我们看一看原理和接口就可以了。
2.1原理
进程A,B可以相互为读写段,一端把数据放到队列里,一端去拿。
那如何保证两个进程不会拿到自己的,而去拿对方的呢。
这个队列内核数据结构中有一个type,用来标识,这个信息是谁发的,不是自己的不拿。
2.2接口
创建一个消息队列
看到没这些参数和共享内存的参数非常相似。
成功是返回消息队列标识符,失败返回-1。
向消息队列中放数据
msgp:发送的数据
msgsz:数据大小
msgflg:默认为0
接收数据
msgp:接收数据放到这里
msgsz:大小
msgtyp:类型
删除队列
这些接口都和共享内核相似。
3.信号量
关于信号量这里补充一些概念,也是为了后面的学习。
3.1信号量是什么
本质上是一个计数器,通常用来表示公共资源中,资源数量的多少问题。
信号量本质是一个计数器,那可以直接设置一个全局变量用来充当计数器吗?
不可以的,就如在匿名管道,设置一个全局变量,因为写时拷贝,父子进程看到的根本不是同一个全局变量。
进程通信之前要看到同一份资源,然后才能通信。
公共资源:被多个进程同时可以访问的资源。
以管道的方式通信的双方,注意到写端没写,读端一直在阻塞等待,读端没读,写端写完也在阻塞等待等等,而共享内存的方式呢,不管写端是否写完,读端一直在读。假设写一段数据,结果数据没写完就读。就造成了问题,这些数据就在共享内存中没有被保护。
访问没有被保护的公共资源导致数据不一致的问题。
我们来捋一捋这个过程。
为什么要让不同的进程看到同一份资源呢?
因为我想通信,让进程之间实现协同,但是进程具有独立性,因此需要先让进程看到同一份资源。 提出了方法,然后也引入了新的问题------>数据不一致问题。
我们未来将被保护起来的公共资源:临界资源
进程大部分的资源是独立的。
资源(内存,文件,网络)是要被使用的,如何被进程使用呢?
一定是该进程有对应的代码来访问这部分临界资源,这个代码临界区,其他代码叫非临界区。
那如何保护公共资源呢?
互斥和同步
互斥:当有两个进程想访问一个公共资源的时候,我们只能让一个进程进行完整的访问。
同步,在多线程哪里再说。
还有一组概念比较不好理解。
假如我想向缓冲区写一段数据,要求我必须要把这段数据写完你才能读,我没写完你就读不了。对于我来讲,我在写的时候,我要么不写,要写就写完才对你有意义。
这种要么不做,要做就做完,两态的这种情况:原子性。
假设张三要去银行给李四转账200
张三1000 李四1000
1000-200 1000+200
但是网络出现问题,转账失败,那银行不能就不管了,必须要把这200还给张三保持原样。
转账对于我们来说就只有两态,要么不转,要转就转完,虽然可能有中间过程,但是最终结果就是要么不转,要转就转完。不会说正在转账中。
这就是我们所有的原子性。
上面说这么多主要是为了说明,让多进程和多线程用来进行原子性的互斥和同步,信号量是其中一种解决方案。
3.2为什么要信号量
举个例子
去电影票看电影,我是不是只要坐到座位上,这个位置才是属于我的?
并不是,买票(票号,座位号)之后,这个位置在那个时间段就是属于我的。
看电影买票的本质:对放映厅中座位进行进行预定机制。
当我们想要某种资源的时候,我们可以进行预定。
电影院就相当于共享资源。
每个进程想访问某些公共资源时,先申请信号量,申请成功就相当于预定了共享资源的某一部分资源,才能允许进入这个小资源里进行访问,申请失败,就不允许这个基础进入共享资源,进而达到保护共享资源以及其他基础的目的。
所有进程在访问公共资源之前,都必须先申请sem信号量---->必须申请sem信号量的前提,是所有进程必须先看到同一个信号量---->信号量本身就是公共资源---->
信号量是不是也要保护自己的安全呢?(++,- - 操作)---->信号量必须要保护这种操作的安全性,++,- -操作是原子的!!!
++,- -就是我们所说的PV操作
信号量本质是一把计数器,这个计数器可以在多进程环境中,可以被多进程先看到,必须给我们匹配上两种操作,P操作,V操作,让进程对我们的共享资源进行访问。
如果信号量初始值是1,代表共享资源当作整体来使用,一个进程申请成功了,其他进程不能申请------->互斥。
提供互斥功能的信号量---->二元信号量。
这里可能有这样一个问题,进程申请成功了信号量,是有资格去访问共享资源,但具体是去访问那个资源子部分不知道,可能存在多个进程访问同一个资源的问题,(也就是买票(票号有了,座位号还没有))该怎么办?
这部分其实是由我们在写代码时来确认不同进程去访问那个资源的。
3.3接口
获取信号量
nsems:想申请几个信号量
申请成功返回一个信号量集的标识符。失败返回-1。
删除信号量,或者获取信号量属性
semnum:可能你申请很多信号量,这个是信号量对应的下标,申请一个信号量,下标为0,申请10个信号量,假设我想对第10个信号量操作,下标就是9。
cmd:删除,或者获取信号量相关属性。
对信号量做PV操作
对指定信号量,做对应的操作
struct sembuf结构有三个变量
sem_num:对申请的多个信号量,哪一个进行操作。
sem_op:一般只有两种值,一种是1代表++,V操作。一种是-1代表- -,P操作。
sem_flg:默认为0
nspos:有几个这样的结构体。
允许对多个信号量同时进行PV操作。
4.IPC资源的组织方式
我们注意到共享内存,消息队列,和信号量的接口都非常相似。都有struct …id_ds这样的结构体,还有对应描述IPC属性资源的第一个字段都是一样的。
这三种共性可以看出来一个细节,这三种都叫做System V标准的进程间通信。
所谓的标准就是,大家用的方式,接口设计,数据结构的设置都必须遵守某种标准。
那OS如何对管理这些(比如一会申请共享内存,一会消息队列,信号量)的呢?
OS并不是对它们本身进行管理,而是先描述在组织,对匹配的相关资源的内核结构进行管理。
因为当前三种方式的属性的第一个字段都是一样的。
在内核中操作系统可以维护一个指针数组。
结构体第一个成员的地址,在数字上,和结构体对象本身的地址数字是相等的!!
OS有对应的方式知道强转成什么结构体指针。
这就是OS对IPC资源的组织方式。
相关文章:

【linux】进行间通信——共享内存+消息队列+信号量
共享内存消息队列信号量 1.共享内存1.1共享内存的原理1.2共享内存的概念1.3接口的认识1.4实操comm.hppservice.cc (写)clint.cc (读) 1.5共享内存的总结1.6共享内存的内核结构 2.消息队列2.1原理2.2接口 3.信号量3.1信号量是什么3…...

PlantUML基础使用教程
环境搭建 IDEA插件下载 打开IEDA系列IDE,从FIle–>Settings–>Plugins–>Marketplace 进入到插件下载界面,搜索PlantUML,安装PlantUML Integration和PlantUML Parser两个插件,并重启IDE 安装和配置Graphviz 进入官网…...

Redis:新的3种数据类型Bitmaps、HyperLoglog、Geographic
目录 Bitmaps简介常用命令bitmaps与set比较 HyperLoglog简介命令 Geographic简介命令 Bitmaps 简介 位操作字符串。 现代计算机使用二进制(位)作为信息的基本单位,1个字节等于8位,例如“abc”字符串是有3个字节组成,…...

promise时效架构升级方案的实施及落地 | 京东物流技术团队
一、项目背景 为什么需要架构升级 promise时效包含两个子系统:内核时效计算系统(系统核心是时效计算)和组件化时效系统(系统核心是复杂业务处理以及多种时效业务聚合,承接结算下单黄金流程流量)ÿ…...

es的使用方法以及概念
Elasticsearch(简称为ES)是一个开源的搜索引擎,它构建在Lucene搜索引擎之上。它提供了一个分布式、多租户的全文搜索引擎,具有强大的实时分析能力。以下是关于Elasticsearch的一些基本概念和使用方法: 基本概念&#…...

WPF xaml Command用法介绍
WPF (Windows Presentation Foundation) 中的命令设计模式是一种用于分离用户界面逻辑和业务逻辑的方法。在WPF中,这种模式通过命令接口(如 ICommand)实现,使得用户界面组件(如按钮、菜单项等)可以触发不直…...

微信小程序动态生成表单来啦!你再也不需要手写表单了!
dc-vant-form 由于我们在小程序上涉及到数据采集业务,需要经常使用表单,微信小程序的表单使用起来非常麻烦,数据和表单是分离的,每个输入框都需要做数据处理才能实现响应式数据,所以我开发了dc-vant-form,…...

顺序表(数据结构与算法)
✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅ ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ 🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿…...

【大连民族大学C语言CG题库练习题】——判断一个矩阵是另一个矩阵的子矩阵
【问题描述】 从标准输入中输入一个N(N<9)阶矩阵和一个M(M<N)阶矩阵,判断矩阵M是否是N的子矩阵,若是则输出M在N中的起始位置,若不是则输出-1。若矩阵M能与N中某一区域完全相等࿰…...

C#WPF控制模板实例
一、控制模板 ControlTemplate(控件模板)不仅是用于来定义控件的外观、样式, 还可通过控件模板的触发器(ControlTemplate.Triggers)修改控件的行为、响应动画等。 控件模板定义控件的视觉外观,所有的 UI 元素都具有某种外观和行为,例如,Button 具有外观和行为。单击事件或…...
MATLAB Simulink和S7-1200PLC MOBUSTCP通信
MATLAB Simulink和SMART PLC OPC通信详细配置请查看下面文章链接: MATLAB和西门子SMART PLC OPC通信-CSDN博客文章浏览阅读749次,点赞26次,收藏2次。西门子S7-200SMART PLC OPC软件的下载和使用,请查看下面文章Smart 200PLC PC Access SMART OPC通信_基于pc access smart的…...

五、函数的介绍
1、为什么需要函数 (1)当程序足够简单时,一个main函数就可以实现所有功能。随着程序功能的增加、复杂化,超出人的大脑的承受范围,这时一个main函数可能就逻辑不清了。这是就需要把一个大程序分成许多小的模块来组织,于是乎出现了…...

【广州华锐互动VRAR】VR元宇宙技术在气象卫星知识科普中的应用
随着科技的不断发展,虚拟现实(VR)和元宇宙等技术正逐渐走进我们的生活。这些技术为我们提供了一个全新的互动平台,使我们能够以更加直观和生动的方式了解和学习各种知识。在气象天文领域,VR元宇宙技术的应用也日益显现…...

F. Alex‘s whims Codeforces Round 909 (Div. 3) 1899F
Problem - F - Codeforces 题目大意:有q次询问,每次询问给出一个数x,要求构造一棵n个点的树,使得对于每次询问,树上都有一条简单路径的长度等于x,同时每次询问前可以对树进行一次操作,即将一个…...

面试题-5
1.用递归的时候有没有遇到什么问题? 如果一个函数内可以调用函数本身,那么这个就是递归函数 函数内部调用自己 特别注意:写递归必须要有退出条件return 2.如何实现一个深拷贝 深拷贝就是完全拷贝一份新的对象,会在堆内存中开辟新的空间,拷贝的对象被修改后&…...

车载以太网-ARP
文章目录 车载以太网ARP协议ARP协议帧格式ARP报文示例ARP报文完整流程ARP流程报文示例ARP协议测试 车载以太网ARP协议 车载以太网ARP协议是指在车载以太网中使用的ARP协议。ARP(Address Resolution Protocol)是一种用于将IP地址解析为MAC地址的协议。在…...

Kafka学习笔记(三)
目录 第5章 Kafka监控(Kafka Eagle)5.2 修改kafka启动命令5.2 上传压缩包5.3 解压到本地5.4 进入刚才解压的目录5.5 将kafka-eagle-web-1.3.7-bin.tar.gz解压至/opt/module5.6 修改名称5.7 给启动文件执行权限5.8 修改配置文件5.9 添加环境变量5.10 启动…...

JVM-HotSpot虚拟机对象探秘
目录 一、对象的实例化 (一)创建对象的方式 (二)创建对象的步骤 二、对象的内存布局 (一)对象头 (二)实例数据 (三)对齐填充 三、 对象的访问定位 &…...

大模型技术的发展:开源和闭源,究竟谁强谁弱又该何去何从?
一、开源和闭源的优劣势比较 开源和闭源软件都有各自的优劣势,具体比较如下: 安全性:闭源软件的安全性相对较高,因为其源代码不公开,攻击者难以找到漏洞进行攻击。而开源软件由于源代码公开,容易被攻击者发…...

Python学习笔记--自定义元类
四、自定义元类 到现在,我们已经知道元类是什么鬼东西了。 那么,从始至终我们还不知道元类到底有啥用。 只是了解了一下元类。 在了解它有啥用的时候,我们先来了解下怎么自定义元类。 因为只有了解了怎么自定义才能更好的理解它的作用。…...

软件测试 —— 常见的自动化测试架构!
一个自动化测试架构就是一个集成体系,其中定义了一个特殊软件产品的自动化测试规则。这一体系中包含测试功能函数库、测试数据源、测试对象识别标准,以及各种可重用的模块。这些组件作为小的构建模块,被组合起来代表某种商业流程。自动化测试…...

Python 的 @lru_cache() 装饰器
在 Python 标准库的 functools 模块中,有个 lru_cache 装饰器,用于为一个函数添加缓存系统: 存储函数的输入和对应的输出当函数被调用,并且给出了已经缓存过的输入,那么函数不会再运行,而是直接从缓存中获…...

Swift制作打包framework
新建framework项目 设置生成fat包,包括模拟器x86_64和arm64 Buliding Settings -> Architectures -> Build Active Architecture Only 设置为NO 设置打包环境,选择release edit Scheme -> run -> Build configuration 设置为 Release 设置…...

无线WiFi安全渗透与攻防(N.2)WPA渗透-使用airolib-ng创建彩虹表加速
WPA渗透-使用airolib-ng创建彩虹表加速 WPA渗透-使用airolib-ng创建彩虹表加速1.什么是彩虹表?2.渗透wifi1.创建数据库名2.将字典导入数据库3.生成渗透wifi密码的PMK4.生成需要渗透wifi的彩虹表5.渗透wifiWPA渗透-使用airolib-ng创建彩虹表加速 1.什么是彩虹表? 彩虹表是一…...

整形数据和浮点型数据在内存中的存储差别
愿所有美好如期而遇 我们先来看代码,猜猜结果是什么呢? int main() {//以整型数据的方式存储int n 10;float* m (float*)&n;//以整型数据的方式读取printf("%d\n", n);//以浮点型数据的方式2读取printf("%f\n", *m);printf(&…...

【Python基础篇】运算符
博主:👍不许代码码上红 欢迎:🐋点赞、收藏、关注、评论。 格言: 大鹏一日同风起,扶摇直上九万里。 文章目录 一 Python中的运算符二 算术运算符1 Python所有算术运算符的说明2 Python算术运算符的所有操作…...

开启数据库审计 db,extended级别或os级别)并将审计文件存放到/opt/oracle/audit/下
文章目录 1、登录到数据库2、查看审计状态3、创建审计目录4、启用审计5、设置审计文件路径6、再次查看结果 1、登录到数据库 使用SQL*Plus或者其他Oracle数据库客户端登录到数据库。 sqlplus / as sysdba;2、查看审计状态 show parameter audit;目前是DB状态,并且…...

02.webpack中多文件打包
1.module,chunk,bundle的区别 moudle - 各个源码文件,webpack中一切皆是模块chunk - 多模块合并成的,如entry, import(), splitChunkbundle - 最终的输出文件 2.多文件打包配置 2.1 webpack.common.js const path require(path) const HtmlWebpackPl…...

IEEE Standard for SystemVerilog Chapter 22. Compiler directives
22.1 General 此子句描述以下编译器指令(按字母顺序列出): __FILE__ [22.13] __LINE__ [22.13] begin_keywords [22.14] celldefine [22.10] default_net…...

机器学习中的独立和同分布 (IID):假设和影响
一、介绍 在机器学习中,独立和同分布 (IID) 的概念在数据分析、模型训练和评估的各个方面都起着至关重要的作用。IID 假设是确保许多机器学习算法和统计技术的可靠性和有效性的基础。本文探讨了 IID 在机器学习中的重要性、其假设及其对模型开…...