Linux进程间通信

什么是进程间通信

就是两个进程为了完成某个工作而需要互相交流,互相告知双方进度,结果。
原理:先让A,B进程都可以看到一份公共资源,一个往里面写,一个从里面读。
进程是具有独立性的,所以进程和进程之间无法通过交互访问地址来完成,
所以这份资源是由OS提供的内核缓冲区,让两个进程去访问这份公共资源。

通信方式的种类
管道(生命周期随进程)
匿名管道pipe(重点掌握)
命名管道(重点掌握)
System V IPC(生命周期随内核)
System V 消息队列(了解学习)
System V 共享内存(重点掌握)
System V 信号量(了解学习)

匿名管道

名字就告诉我们了,没有名字,那如何让两个进程看到同一份资源呢?
通过父子继承的方式,子进程以父进程的PCB为模板创建自己的PCB,从而也关联了父进程的打开文件(匿名管道)
也就是说:匿名管道仅仅限于由血缘关系的父子进程。而且必须在子进程创建之前去创建匿名管道

在这里插入图片描述

写一个简单的匿名管道通信,只供解释原理。
但是呢,还有很多种特殊的情况:
1,读端和写段都在未关闭的情况下,他们之间会相互阻塞。读端不读,读的少,写端会等。写端不写,写的慢,读端会等。
2,如果关闭读端,写端会受到13号信号。因为都不读了,写端没有意义了。
3,如果写端关闭,读端会读完缓冲区的内容,并且read()最后返回0

#include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #include <string.h>
  5 
  6 int main()
  7 {
  8      int fd_arr[2] = {0};
  9 
 10      //创建成功后, 0是读端,1是写端
 11      if(pipe(fd_arr) < 0)
 12      {
 13        perror("pipe");
 14        exit(-1);
 15      }
 16 
 17      if(fork() == 0)
 18      {
 19        //子进程 去写,关闭相应的读端
 20        close(fd_arr[0]);
 21        const char* ch = "hello chen";                                                                                                        
 22        write(fd_arr[1],ch,strlen(ch));
 23      }
 24      else
 25      {
 26        //父进程,去读,关闭相应的写端
 27        close(fd_arr[1]);
            char ch[64] = {0};
 29        ssize_t s = read(fd_arr[0],ch,64);
 30        ch[s] = 0;
 31 
 32        printf("child to father::%s\n",ch);
 33        
 34      }
 35 
 36 
 37 
 38      return 0;
 39 }
~


在这里插入图片描述

命名管道

由于匿名管道仅仅限于有血缘关系的父子进程,所以引入了命名管道,它可以用于主机上任何进程的交换。
它是一种特殊的文件。匿名管道和命名管道本质原理是相同的:都是OS提供内核缓冲区
1,而且命名管道的文件名仅仅是缓冲区的标识符,如果正在通信的进程,就算删除了也不受影响
2,大小永远是0(因为不会把数据刷新到管道文件里面),还有管道文件的作用仅仅是缓冲区的标识符。

通信原理:
在这里插入图片描述

让两个进程分别包含通一个.h头文件,通过宏定义让其做到看同一份资源的目的。

 #include <sys/types.h>
  2 #include <sys/stat.h>
  3 #include <fcntl.h>
  4 #include <stdlib.h>
  5 #include <stdio.h>
  6 #include <unistd.h>
  8 #define MYFIFO "./myfifo  //各自包含头文件,就做到了拿到管道文件的文件名

一个进程以写的方式打开管道文件

    #include "commond.h"
  3 int main()
  4 {
  5     int fd = open(MYFIFO,O_WRONLY);
  6     if(fd < 0)
  7     {
  8       perror("opne fail");
  9       exit(-1);
 10     }
 11 
 12     while(1)
 13     {
 14        printf("girlfriend say:#");
 15        fflush(stdout);
 16 
 17        char ch[64] = {0};
 18        read(1,ch,64);                                                                                                                        
 19        write(fd,ch,64);
 20     }
 21 
 22     return 0;
 23 }

一个进程以读方式打开管道文件

     #include "commond.h"2 
  3 int main()
  4 {
  5      umask(0); // 文件权限 = default & (~umask)6 
  7      if(mkfifo(MYFIFO,0666) < 0)   //创建管道文件
  8      {
  9        perror("mkfifo");
 10        exit(-1);
 11      }
 12     
 13      //我们只需要读就可以了      
       int fd = open(MYFIFO,O_RDONLY);
 15      if(fd < 0)
 16      {
 17        perror("errror");
 18        exit(-1);
 19      }
 20     
 21      while(1)
 22      {                                                                                                                                       
 23          char ch[64] = {0};
 24          ssize_t s = read(fd,ch,sizeof(ch));
 25          if(s < 0)
 26          {
 27            perror("read fail");
                exit(-1);
 29          }
 30          else if(s == 0)
 31          {
 32            printf("girl go away\n");
 33            break;
 34          }
 35          else
 36          {
 37            ch[s-1] = 0; //会把\n也读进去38            
               printf("girlfriend say to boy:%s",ch);
 39          }
 40      }
 41 
 42 
 43      close(fd);
 44      return 0;
 45 }

在这里插入图片描述

共享内存

通信速度最快
会存在多个,进程A和B,C和D,,,,都要通信,意味着共享内存会存在多份。
OS如何管理呢? 先描述后组织,对共享内存的描述肯定是在结构体里面。
A和B,C和D如何保证能准确看到对应的共享内存呢? 所以共享内存的结构体肯定封装了一个唯一标识符。

因为共享内存是OS提供的,所以它的生命周期是随内核的。如何删除共享内存呢?函数调用(最终会去调用系统调用),OS重启
在这里插入图片描述

如何让进程通过共享内存来交互呢?
1,通过某种系统调用,在内存中创建一份内存空间。
2,通过某种调用,让要通信的进程挂接到这份空间上。
3,通信完成后去掉挂接。
4,释放共享内存。

先看看申请共享内存的系统调用

在这里插入图片描述
其他的共享内存操作:
在这里插入图片描述
.h头文件

 1 #include <sys/types.h>
  2 #include <sys/stat.h>
  3 #include <fcntl.h>
  4 #include <stdlib.h>
  5 #include <stdio.h>
  6 #include <unistd.h>
  7 #include <sys/ipc.h>
  8 #include <sys/shm.h>                                                                                                                         
  9 
 10 
 11 #define MYPATH "./"
 12 #define PR0_ID 0x11223344

server.c

   #include "commond.h"
  2 
  3 
  4 int main()
  5 {
  6 
  7      key_t key = ftok(MYPATH,PR0_ID); //生成OS层面共享内存的标识符
  8      if(key < 0)
  9      {
 10         perror("ftok");
 11         exit(-1);
 12      }
 13      
 14      //printf("key::%d\n",key);
 15      
 16      //生成共享内存,生成全新的,并且指明权限(类似于文件)
 17      int shmid = shmget(key,4096,IPC_CREAT | IPC_EXCL | 0664);
 18      if(shmid < 0)
 19      {
 20        perror("shmget");
 21        exit(-1);
 22      }                                                                                                                                       
 23 
 24     //挂接
 25      char* shmsg = (char*)shmat(shmid,NULL,0);
 26      //printf("挂接成功\n");
 27      sleep(15);
        //读出共享内存的数据
 30      while(1)                                                                                                                                
 31      {
 32        printf("%s\n",shmsg);
 33        sleep(1);
 34      }
 35     
 36      
 37      //去挂接
 38      shmdt(shmsg);
 39 
 40      //删除共享内存
 41      shmctl(shmid,IPC_RMID,NULL);
 42      return 0;
 43 }

client.c

    #include "commond.h"
  2 
  3 
  4 int main()
  5 {
  6     //获得相同的共享内存标识符
  7     key_t key = ftok(MYPATH,PR0_ID);
  8     if(key < 0)
  9     {
 10       perror("ftok");
 11       exit(-1);
 12     }
 13 
 14     int shmid = shmget(key,4096,IPC_CREAT);//如果存在则返回已经存在的
 15 
 16     //挂接
 17     char* shmsg = (char*)shmat(shmid,NULL,0);
 18     sleep(10); 
 19 
 20     //写入共享内存的数据
 21     char c = 'A';
 22     while(c <= 'Z')                                                                                                                          
 23     {
 24         shmsg[c-'A'] = c;
 25         c++;
 26         shmsg[c-'A'] = 0;
 27         sleep(2);
   } 
 29 
 30     //去挂接
 31     shmdt(shmsg);
 32 
 33     //我们不需要去删除
 34 
 35     return 0;
 36 }


在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

通过全部用例

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值