进程通信——匿名管道实现和验证

来源:互联网 发布:gommdb数据库编辑器 编辑:程序博客网 时间:2024/06/04 18:34

今天我们来分享一下,Linux中关于进程通行中最简单的匿名管道的实现和相关性质的验证。

进程通信的原理是:多个进程看到同一份公共资源(文件),能对该资源进行相应操作,不同进程间即可进行通信。一般有操作系统(内核)提供这一公共资源。今天我们利用匿名管道来实现进程通信。

首先介绍一下,匿名管道的特点:

1.匿名管道只能实现单向通信。

2.匿名管道只能实现有血缘关系的进程之间的通信。

3.管道是一个随进程的文件,即当进程退出时,管道文件不存在。

4.管道的数据通信是基于数或者字节流的通信。

5.管道内部实现同步互斥,满足安全性,保证数据的一致性。

 

接着,举例父子进程的通信来说明匿名管道的通信过程。

A.利用pipe函数建立匿名管道,得到管道的读写文件描述符。

B.fork创建子进程。由于管道的读写文件描述符属于数据,子进程会依照父进程复制一份,即父子同时拥有指向管道文件的读写文件描述符,用有一份公共的管道文件,就拥有了进程通行的条件。

C.由于匿名管道只能实现进程间的单项通信,所以需要手动关闭父子进程冗余的读写端(读写文件描述符)。

注:子写父读,关闭子进程的读端和父进程的写端。需求不同则反之。

D.父子进程进行相应的读写,实现进程通信。

图解如下:

 

我们需要验证以下四种情况:

A.读端不关闭,且不读取管道内容,写端不断向管道写内容,当管道被写满,写端只能阻塞式等待。

部分代码截图和运行结果如下:

 

 

B.写端不关闭,且不向管道写内容,读端不断读取管道内容,当管道中数据读完,读端只能阻塞式等待。

部分代码截图和运行结果如下:

 

 

 

C.读端先于写端关闭,写端收到异常信号退出。

部分代码截图和运行结果如下:

 

 

D.写端先于读端关闭,当读到0时,即读到文件结尾,退出。

部分代码截图和运行结果如下:

 

 

 

实现进程通信——匿名管道,代码如下:

#include<stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<stdlib.h>#include<unistd.h>#include<string.h>  int main() {      umask(0);      int pfd[2];      if(pipe(pfd) < 0){         perror("pipe wrong!\n");          exit(1);      }        pid_t id = fork();        if(id<0){          perror("wrong!\n");          exit(1);      }  if(id == 0){//child          close(pfd[0]);          int i = 0;          char* tmp = "hello !";  //      while(1){ //          i++; //          if(i < 5){ //              printf("child: %s, num: %d\n", tmp, i); //              write(pfd[1], tmp, strlen(tmp)); //          } //          else//i>=5 //          { //              exit(1); //          }  //      sleep(1); //      } //      exit(1);          while(1){         printf("child: %s, num: %d \n", tmp, i);         i++;         if(i>10)return 0; write(pfd[1], tmp, strlen(tmp));          }      }      else{//parent      int status;      close(pfd[1]);      char tmp[1024];        int i=0;      while(1){          ssize_t s = read(pfd[0], tmp, sizeof(tmp)-1);  //      if(i>5) close(pfd[0]);  //      i++;          if(s>0){              tmp[s] = 0;              printf("parent:%s\n", tmp);          }          else if(s == 0){//child quit,so parent will quit              printf("child quit,so parent will quit!\n");              sleep(5);              break;          }  //      else{//wrong  //          printf("read wrong!\n");  //          int status;  //          pid_t s = waitpid(id, &status, 0);  //          if(s>0){  //       printf("waitpid success! sig:%d, exitCode: %d\n",\  //              WIFEXITED(status),WEXITSTATUS(status) );  //              }  //          exit(2);  //      }      }          if(waitpid(id, &status, 0)>0){          printf("waitpid success! sig:%d, exitCode: %d\n",\          WIFEXITED(status),WEXITSTATUS(status) );          }      }      return 0;  }


分享如上,欢迎斧正!

注:代码虽乱但全。若有错误和遗漏,请参见代码截图或评论!