Linux编程练习 --进程间通信1--无名管道

时间:2021-12-04 04:40:54

进程间通信系列--管道

管道可以说是最古老的IPC形式,所谓管道,是指进程间建立的一条通信的通道,从本质上看,管道是UNIX文件概念的推广管道通信的介质是文件,先看一下管道的特点:

 

1.管道的特点:

  (1)管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;

  (2)无名管道只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);后来发展了FIFO(也称有名管道)

  (3)单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。

   (4)数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

 

2.无名管道API及操作:

头文件:#include <unistd.h>

数据成员:int pipe_fd[2];

管道创建:int pipe(int fd[2])

    该函数创建的管道的两端处于一个进程中间,在实际应用中没有太大意义,因此,一个进程在由pipe()创建管道后,一般再fork一个子进程,然后通过管道实现父子进程间的通信(因此也不难推出,只要两个进程中存在亲缘关系,这里的亲缘关系指的是具有共同的祖先,都可以采用管道方式来进行通信)。

管道读写:

管道两端可分别用描述字fd[0]以及fd[1]来描述,管道读端:fd[0],管道写端:fd[1];

读管道规则:

 关闭管道的写端:close (fd[WRITE]);

读出:read(fd[READ],string,strlen(string));

读出后关闭管道的读端:close(fd[REAd]);

 

写管道规则:

关闭管道的读端:close(fd[REAd]);

写入:write(fd[WRITE],string,strlen(string));

写入后关闭管道的写端:close (fd[WRITE]);

 

下面练习一个简单的单管道通信:

父进程写数据,子进程负责读出数据

 

[cpp] view plaincopy
  1. /**************  
  2.   * readtest.c *  
  3.    
  4. **************/   
  5. #include <unistd.h>   
  6. #include <sys/types.h>   
  7. #include <errno.h>   
  8. #define     READ    0  
  9. #define     WRITE   1  
  10. main()   
  11. {     
  12.     int pipe_fd[2];       
  13.     pid_t pid;    
  14.     char r_buf[100];      
  15.     char w_buf[32];       
  16.     char* p_wbuf;   
  17.     int r_num;    
  18.     int cmd;      
  19.     memset(r_buf,0,sizeof(r_buf));    
  20.     memset(w_buf,0,sizeof(r_buf));    
  21.     p_wbuf=w_buf;     
  22.     if(pipe(pipe_fd)<0)        
  23.     {         
  24.         printf("pipe create error ");         
  25.         return -1;        
  26.     }   
  27.       
  28.     if((pid=fork())==0) //子进程读        
  29.     {     
  30.         close(pipe_fd[WRITE]);    
  31.         sleep(3);           //确保父进程关闭写端   
  32.         r_num=read(pipe_fd[READ],r_buf,100);   
  33.         printf( "read num is %d the data read from the pipe is %s /n",r_num,r_buf);       
  34.         close(pipe_fd[READ]);     
  35.         exit();           
  36.     }     
  37.     else if(pid>0)   //父进程写  
  38.     {         
  39.         close(pipe_fd[READ]);         
  40.         strcpy(w_buf,"hello world!/n");           
  41.         if(write(pipe_fd[WRITE],w_buf,strlen(w_buf))==-1)         
  42.             printf("parent write over/n ");           
  43.         close(pipe_fd[WRITE]);        
  44.         printf("parent close fd[WRITE] over /n");         
  45.         sleep(10);   
  46.     }     
  47. }   

编译运行,看到预期结果

 

3.利用两个管道进行双向通信

(1)创建两个管道:管道1(父->子),管道2(子->父)

(2)fork()产生子进程

(3)父进程:close(fd1[READ]); close(fd2[WRITE]);

(4)子进程:close(fd1[WRITE]); close(fd2[READ]);

下面做一个练习,是利用双向通信实现父子进程协作把整数x从1加到10

[cpp] view plaincopy
  1. #include <unistd.h>  
  2. #include <sys/stat.h>  
  3. #include <sys/types.h>  
  4. #include <stdio.h>  
  5. #include <fcntl.h>  
  6. #define MAXLINE 1024  
  7. #define READ    0  
  8. #define WRITE   1  
  9. main(void)  
  10. {  
  11.     int x;  
  12.     pid_t pid;  
  13.     int pipe1[2],pipe2[2];  
  14.     /*初始化管道*/  
  15.     pipe(pipe1);  
  16.     pipe(pipe2);  
  17.     pid = fork();  
  18.     if(pid < 0)  
  19.     {  
  20.         printf("create process error!/n");  
  21.         exit(1);  
  22.     }  
  23.     if(pid == 0)        //子进程  
  24.     {  
  25.         close(pipe1[WRITE]);  
  26.         close(pipe2[READ]);  
  27.         do  
  28.         {  
  29.             read(pipe1[READ],&x,sizeof(int));  
  30.             printf("child %d read: %d/n",getpid(),x++);  
  31.             write(pipe2[WRITE],&x,sizeof(int));  
  32.         }while(x<=9);  
  33.         //读写完成后,关闭管道  
  34.         close(pipe1[READ]);  
  35.         close(pipe2[WRITE]);  
  36.         exit(0);  
  37.     }  
  38.     else if(pid > 0) //父进程  
  39.     {  
  40.         close(pipe2[WRITE]);  
  41.         close(pipe1[READ]);  
  42.         x = 1;  
  43.         //每次循环向管道1 的1 端写入变量X 的值,并从  
  44.         //管道2 的0 端读一整数写入X 再对X 加1,直到X 大于10  
  45.         do{  
  46.             write(pipe1[WRITE],&x,sizeof(int));  
  47.             read(pipe2[READ],&x,sizeof(int));  
  48.             printf("parent %d read: %d/n",getpid(),x++);  
  49.         }while(x<=9);  
  50.         //读写完成后,关闭管道  
  51.         close(pipe1[WRITE]);  
  52.         close(pipe2[READ]);  
  53.         waitpid(pid,NULL,0);  
  54.         exit(0);  
  55.     }  
  56. }