linux進程間通信之管道(無名管道pipe)實現全雙工雙向通信


管道是什么:
1. 管道只能用於具有親緣關系的進程之間通信。
2.管道是一種單工或者說半雙工的通信方式,傳遞信息的方向是固定的,只能由一端傳遞到另一端。

頭文件及函數原型:
#include <unistd.h>
int pipe(int fd[2]);

當用pipe 創建管道后,兩個文件描述符fd[0],fd[1]就可以使用了,其中fd[0]用於讀取,fd[1]用於寫入。調用管道pipe返回值0表示成功,返回值-1表示失敗。


pipe函數創建管道后,接着fork出子進程,子進程繼承父進程管道。

代碼舉例來看:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <unistd.h>
  6. #define MAX_DATA_LEN 256
  7. #define DELAY_TIME 1
  8. int main() {
  9.     pid_t pid;
  10.     char buf[MAX_DATA_LEN];
  11.     const char *data="Pipe Test";
  12.     int real_read,real_write;
  13.     int pipe_fd[2];
  14.     memset((void*)buf,0,sizeof(buf));
  15.     if(pipe(pipe_fd)<0){
  16.         perror("Pipe create error!\n");
  17.         exit(1);
  18.     }
  19.         
  20.     if ((pid=fork())<0) {
  21.         perror("Fork error!\n");
  22.         exit(1);
  23.     } else if (pid==0) {
  24.         close(pipe_fd[1]);
  25.         sleep(DELAY_TIME*3);
  26.         if ((real_read=read(pipe_fd[0],buf,MAX_DATA_LEN))>0) {
  27.             printf("Child receive %d bytes from pipe: '%s'.\n",real_read,buf);
  28.         }
  29.         close(pipe_fd[0]);
  30.         exit(0);
  31.     } else {
  32.         close(pipe_fd[0]);
  33.         sleep(DELAY_TIME);
  34.         if ((real_write=write(pipe_fd[1],data,strlen(data)))>0) {
  35.             printf("Parent write %d bytes into pipe: '%s'.\n",real_write,data);
  36.         }
  37.         close(pipe_fd[1]);
  38.         waitpid(pid,NULL,0);
  39.         exit(0);
  40.     }
  41. }
復制代碼

運行輸出:
Parent write 9 bytes into pipe: 'Pipe Test'.
Child receive 9 bytes from pipe: 'Pipe Test'.

 

 

上述代碼只能從父進程向子進程傳遞,如何從子進程向父進程傳遞呢?我們看到父進程關閉了管道讀取端“close(pipe_fd[0]);”,子進程關閉了管道寫入端“close(pipe_fd[1]);”,如果取消關閉這兩個端,是否能夠實現子進程向父進程傳遞呢。
父進程先發送,子進程接收,然后子進程再發送,父進程再接收,實現全雙工互相通信,期望運行結果如下:
Parent write 9 bytes into pipe: 'Pipe Test'.
Child receive 9 bytes from pipe: 'Pipe Test'.
Child write 9 bytes from pipe: 'Pipe Test'.
Parent receive 9 bytes from pipe: 'Pipe Test'.

修改代碼如下:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <unistd.h>
  6. #define MAX_DATA_LEN 256
  7. #define DELAY_TIME 1
  8. int main() {
  9.     pid_t pid;
  10.     char buf[MAX_DATA_LEN];
  11.     const char *data="Pipe Test";
  12.     int real_read,real_write;
  13.     int pipe_fd[2];
  14.     memset((void*)buf,0,sizeof(buf));
  15.     if(pipe(pipe_fd)<0){
  16.         perror("Pipe create error!\n");
  17.         exit(1);
  18.     }
  19.         
  20.     if ((pid=fork())<0) {
  21.         perror("Fork error!\n");
  22.         exit(1);
  23.     } else if (pid==0) {
  24.         //close(pipe_fd[1]);
  25.         sleep(DELAY_TIME*3);
  26.         if ((real_read=read(pipe_fd[0],buf,MAX_DATA_LEN))>0) {
  27.             printf("Child receive %d bytes from pipe: '%s'.\n",real_read,buf);
  28.         }
  29.                 
  30.                 if ((real_write=write(pipe_fd[1],data,strlen(data)))>0) {
  31.             printf("Child write %d bytes into pipe: '%s'.\n",real_write,data);
  32.         }
  33.         close(pipe_fd[0]);
  34.         exit(0);
  35.     } else {
  36.         //close(pipe_fd[0]);
  37.         sleep(DELAY_TIME);
  38.         if ((real_write=write(pipe_fd[1],data,strlen(data)))>0) {
  39.             printf("Parent write %d bytes into pipe: '%s'.\n",real_write,data);
  40.         }
  41.                 
  42.         if ((real_read=read(pipe_fd[0],buf,MAX_DATA_LEN))>0) {
  43.             printf("Parent receive %d bytes from pipe: '%s'.\n",real_read,buf);
  44.         }
  45.         close(pipe_fd[1]);
  46.         waitpid(pid,NULL,0);
  47.         exit(0);
  48.     }
  49. }
復制代碼


但是實際運行如下:
Parent write 9 bytes into pipe: 'Pipe Test'.
Parent receive 9 bytes from pipe: 'Pipe Test'.


可以看到,父進程發送的數據被父進程自己接收了,子進程讀不到數據被阻塞了。顯然這種方法不行。

 

 

因為管道是單工的,只能固定從一個方向傳遞到另一個方向。
要實現互相通信,一個管道是不行的,可以創建兩個管道,一個管道是父寫子讀,另一個是子寫父讀。
代碼如下:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <unistd.h>
  6. #define MAX_DATA_LEN 256
  7. #define DELAY_TIME 1
  8. int main() {
  9.     pid_t pid;
  10.     char buf[MAX_DATA_LEN];
  11.     const char *data="Pipe Test";
  12.     int real_read,real_write;
  13.     int pipe_fd[2],pipe_fd2[2];
  14.     memset((void*)buf,0,sizeof(buf));
  15.     if(pipe(pipe_fd)<0){
  16.         perror("Pipe create error!\n");
  17.         exit(1);
  18.     }
  19.         
  20.         if(pipe(pipe_fd2)<0){
  21.         perror("Pipe create error!\n");
  22.         exit(1);
  23.     }
  24.     if ((pid=fork())<0) {
  25.         perror("Fork error!\n");
  26.         exit(1);
  27.     } else if (pid==0) {
  28.         close(pipe_fd[1]);
  29.                 close(pipe_fd2[0]);
  30.         sleep(DELAY_TIME*3);
  31.         if ((real_read=read(pipe_fd[0],buf,MAX_DATA_LEN))>0) {
  32.             printf("Child receive %d bytes from pipe: '%s'.\n",real_read,buf);
  33.         }
  34.                 if ((real_write=write(pipe_fd2[1],data,strlen(data)))>0) {
  35.             printf("Child write %d bytes into pipe: '%s'.\n",real_write,data);
  36.         }
  37.         close(pipe_fd[0]);
  38.                 close(pipe_fd2[1]);
  39.         exit(0);
  40.     } else {
  41.         close(pipe_fd[0]);
  42.                 close(pipe_fd2[1]);
  43.         sleep(DELAY_TIME);
  44.         if ((real_write=write(pipe_fd[1],data,strlen(data)))>0) {
  45.             printf("Parent write %d bytes into pipe: '%s'.\n",real_write,data);
  46.         }
  47.                 if ((real_read=read(pipe_fd2[0],buf,MAX_DATA_LEN))>0) {
  48.             printf("Parent  receive %d bytes from pipe: '%s'.\n",real_read,buf);
  49.         }
  50.         close(pipe_fd[1]);
  51.                 close(pipe_fd2[0]);
  52.         waitpid(pid,NULL,0);
  53.         exit(0);
  54.     }
  55. }
復制代碼

運行結果:
Parent write 9 bytes into pipe: 'Pipe Test'.
Child receive 9 bytes from pipe: 'Pipe Test'.
Child write 9 bytes into pipe: 'Pipe Test'.
Parent  receive 9 bytes from pipe: 'Pipe Test'.


可以看到,創建了兩個管道 “int pipe_fd[2],pipe_fd2[2];”,
pipe_fd 是父寫子讀,pipe_fd2是子寫父讀,通過兩個管道,實現了進程的全雙工互相通信。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM