【Linux】进程间通信

目录

匿名管道:

代码演示: 

管道的特性: 

验证部分特性: 

管道大小

命名管道:

命令行代码实验:

命名管道实现的相关代码:

Client端:

server端:

makefile:

运行结果:


进程间通信的本质:让不同的进程,能看到同一份系统资源(系统通过某种方式提供的系统内存)

【Linux】进程间通信_第1张图片管道通信:

匿名管道 and 命名管道:底层的原理是基本一样的

匿名管道:

供具有血缘关系的进程,进行进程间通信(保证不同的进程,看到同一份资源)(常见于父子)

 【Linux】进程间通信_第2张图片

父子进程关闭不需要的文件描述符,来达到构建单向通信的信道的目的

这里有2个问题:

为什么需要关,那么曾经为什么要打开呢?

如果不打开读写,子进程拿到的文件打开方式必定和父进程一样,无法通信,同时更加灵活!

为什么要关闭?

一方面证明管道单向通信的特性,主要为了防止误操作

int pipe(int pipefd[2])  

输出型参数,通过调用pipe,拿到刚刚打开的管道文件的描述符

2个fd,对应于一个读,一个写

代码演示: 

#include                                                                                                                                                                                                                                                             
  2 #include
  3 #include
  4 #include
  5 #include
  6 int main()
  7 {
  8   int pipe_fd[2] = {0};
  9   if(pipe(pipe_fd) < 0)
 10   {
 11     perror("pipe");
 12     return 1;
 13   }
 14 
 15   printf("%d,%d\n",pipe_fd[0],pipe_fd[1]);
 16 
 17   pid_t id = fork();
 18   if(id < 0)
 19   {
 20     perror("fork");
 21     return 2;
 22   }
 23   else if(id==0)
 24   {
 25     //child让子进程进行写入
 26     close(pipe_fd[0]);
 27 
 28 
 29     const char*msg = "我是子进程\n";
 30     int count = 5;
 31     while(count)
 32     {
 33       write(pipe_fd[1],msg,strlen(msg));//向管道当中写入的功能
 34       sleep(1);
 35       count--;
 36     }
 37     close(pipe_fd[1]);
 38     exit(0);
 39   }
 40   else{
 41     //child让父进行读取
 42     close(pipe_fd[1]);
 43     char buffer[64];
 44     while(1)
 45     {
 46       buffer[0] = 0;
 47       ssize_t size = read(pipe_fd[0],buffer,sizeof(buffer)-1);//管道中读取
 48       if(size > 0)
 49       {
 50         buffer[size] = 0;
 51         printf("从子进程中来的:%s\n",buffer);
 52       }
 53       else if(size == 0)
 54       {
 55         printf("管道文件关闭,子进程退出\n");
 56         break;
 57       }
 58       else{
 59         break;
 60       }
 61     }
 62     int status = 0;
 63     if(waitpid(id,&status,0)>0)
 64     {
 65       printf("子进程退出,等待成功\n");
 66     }
 67     close(pipe_fd[0]);
 68   }
 69   return 0;
 70 }

【Linux】进程间通信_第3张图片

管道的特性: 

如果管道里面已经没有消息,父进程(读端)在干什么?

等待,在等管道内部有数据就绪

如果管道里面写端已经写满了,继续写入,还能写吗?

不能,等待管道内部有空闲空间(等父进程读走)

第一:管道自带同步机制

第二:管道是单向通信的

第三:管道是面向字节流的

第四:管道只能保证具有血缘关系的进程通信,常用于父子

第五:管道可以保证一定程度的数据读取的原子性

第六:进程退出,曾经打开的文件也会被关掉,管道也是文件,所以管道的生命周期随进程

验证部分特性: 

read端 write端 结果
不读 write阻塞
不写 read阻塞
不写 & 关闭 read读取到0,文件结束!
不读 & 关闭 write被OS发送的SIGPIPE杀掉

读取关闭,一直在写

毫无意义,一直在写,本质就是在浪费系统资源,写进程会立马被OS终止掉!(通过发送信号终止子进程)

【Linux】进程间通信_第4张图片

管道大小

64KB(非原子性写入管道当中的单元大小)

4KB(原子性写入的)

命名管道:

理解命名管道的原理

1:先保证两个进程能看到同一份资源

普通文件,是需要将数据刷新到磁盘的,持久化存储

命令行代码实验:

【Linux】进程间通信_第5张图片

命名管道实现的相关代码:

Client端:

#include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 
  8 #define FIFO "./fifo"
  9 int main()
 10 {
 11   int fd = open(FIFO,O_WRONLY);
 12   if(fd < 0)
 13   {
 14     perror("open");
 15     return 2;
 16   }
 17   char buffer[128];
 18   while(1)
 19   {
 20     printf("Please Enter");
 21     fflush(stdout);                                                                                                                                                                         
 22     buffer[0] = 0;
 23     ssize_t s = read(0,buffer,sizeof(buffer));//从标准输入里读数据
 24     if(s > 0)
 25     {
 26       buffer[s] = 0;
 27       write(fd,buffer,strlen(buffer));//写到管道文件
 28     }
 29     else if(s == 0)
 30     {
 31       printf("client quit\n");
 32       break;
 33     }
 34     else{
 35       break;
 36     }
 37   }
 38   close(fd);
 39   return 0;
 40 }

server端:

#include
  2 #include
  3 #include
  4 #include
  5 #include
  6 
  7 #define FIFO "./fifo"
  8 int main()
  9 {
 10   int ret = mkfifo(FIFO,0644);
 11   if(ret < 0)
 12   {
 13     perror("mkfifo");
 14     return 1;
 15   }
 16   int fd = open(FIFO,O_RDONLY);
 17   if(fd < 0)
 18   {
 19     perror("open");
 20     return 2;
 21   }
 22   char buffer[128];                                                                                                                                                                         
 23   while(1)
 24   {
 25     buffer[0] = 0;
 26     ssize_t s = read(fd,buffer,sizeof(buffer));
 27     if(s > 0)
 28     {
 29       buffer[s] = 0;
 30       printf("client : %s\n",buffer);
 31     }
 32     else if(s == 0)
 33     {
 34       printf("client quit\n");
 35       break;
 36     }
 37     else{
 38       break;
 39     }
 40   }
 41   close(fd);
 42   return 0;
 43 }
~

makefile:

client:client.c
  5     gcc -o $@ $^
  6 server:ser.c
  7     gcc -o $@ $^
  8 .PHONY:clean
  9 clean:
 10   rm -f client ser fifo              

运行结果:

【Linux】进程间通信_第6张图片

你可能感兴趣的