【linux】进行间通信——共享内存+消息队列+信号量
共享内存+消息队列+信号量
- 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学习笔记--自定义元类
四、自定义元类 到现在,我们已经知道元类是什么鬼东西了。 那么,从始至终我们还不知道元类到底有啥用。 只是了解了一下元类。 在了解它有啥用的时候,我们先来了解下怎么自定义元类。 因为只有了解了怎么自定义才能更好的理解它的作用。…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
