【Linux下】进程间通信( 三 )

<0){perror("mkfifo");return 1;}//打开管道文件int fd=open(PIPE_NAME,O_RDWR);if(fd==1){printf("fd fail\n");}while(1){printf("#请输入 : ");fflush(stdout);char buffer[64]={0};ssize_t s=read(0,buffer,sizeof(buffer)-1);if(s>0){buffer[s-1]='\0';printf("%s\n",buffer);write(fd,buffer,strlen(buffer));}else{perror("read");break;}}return 0;}
读端代吗:
#include "com.h"#include int main(){umask(0000);//打开管道文件int fd=open(PIPE_NAME,O_RDONLY);if(fd<0){perror("open");return 2;}while(1){sleep(1);char buffer[64]={0};ssize_t s=read(fd,buffer,sizeof(buffer))-1;if(s>0){//可以定制服务if(strcmp(buffer,"show")==0){pid_t id=fork();if(id==0){execl("/usr/bin/ls","ls",NULL);exit(0);}else{//parentwaitpid(-1,NULL,0);}}else {printf("%s\n",buffer);} }else if(s==0){printf("client quit\n");}else{perror("read");}}return 0;}
管道实现进程间通信的本质
我们现在大致知道了管道实现进程间通信实际上是不同的进程对管道文件进行写入和读取实现的,而本质其底层是怎么实现的呢?
先来回忆一下我之前博客写的,当我们向普通文件写入的过程是怎么样
进程1调用系统调用write将数据拷贝进test.txt的文件缓冲区中,而后系统调用write又会调用驱动层的写方法将数据写入到磁盘里去
所以进程1调用write函数,实际上write函数做了俩步
将数据拷贝到内核级别的文件缓冲区去调用驱动层的写方法将数据写入到磁盘中去
而如果我们将第二步,换成另外一个数据将数据读走,不就实现了进程间通信吗?–俩进程通过os级别文件缓冲区进行通信
而这实际上就是管道通信的实现原理
匿名管道vs命名管道V
而下面主要介绍 V共享内存
V共享内存
共享内存空间示意图
如图:共享内存同前面的管道一般,也是让不同进程看见同一资源
使用共享内存的步骤:
通过系统调用接口在物理内存里创建出一块内存 --创建共享内存
通过调用将进程挂接该内存 即在我们的页表进行映射–挂接共享内存
释放共享内存的步骤:
去挂接
释放共享内存
查看 V资源的命令行指令
ipcs
作用:查看共享内存相关信息
选项:
创建或获取共享内存
ftok
作用:创建出key值 (在系统层面进行唯一标识)
: 自定义的路劲名
: 自定义的id名
返回值:
成功返回0 失败返回-1 并设置错误码
作用: 开辟共享内存 或者获取共享内存的shmid
key: 即我们上面,通过ftok获取的共享内存在系统层面的标识符,不同的进程就是通过相同的key值找到同一个共享内存(注:一个进程挂接的共享内存可能不止一个)
size: 我们所需要的共享内存空间大小,而我们一般开辟都是4kb的整数倍 因为我们os系统开辟都是以内存页(内存页单位大小为:4096 byte)为单位给我们共享内存开辟的
例如: 我们将size填成4097个字节,我们使用起来就是按4097个字节来使用的,而os开辟时实际上并不是直接开辟了4097个字节,而是按照俩个内存页大小给我们开辟的,但我们最后使用起来还是4097个字节,因为如果os背着我们多开空间,可能会造成本该越界访问的操作没有被检测出来(os背不起这个锅),
:
常用:
: 单独使用时,作用为当该共享内存空间不存在时,即创建之,若存在就获取他的shimd
: 单独使用没有意义,需和起用作用为当该共享内存空间不存在时,即创建之,若存在就返回错误,作用为保证我们使用的是没有被使用过的内存空间
释放共享内存 法一:使用系统调用接口
int id=shmctl(shmid, IPC_RMID, NULL );