Linux系统编程—有名管道

系统 Linux
管道,又名「无名管理」,或「匿名管道」,管道是一种非常基本,也是使用非常频繁的IPC方式。

一、管道的概念

管道,又名「无名管理」,或「匿名管道」,管道是一种非常基本,也是使用非常频繁的IPC方式。

[[345252]]

1. 管道本质

  • 管道的本质也是一种文件,不过是伪文件,实际上是一块内核缓冲区,大小4K;
  • 管道创建以后会产生两个文件描述符,一个是读端,另一个是写端;
  • 管道里的数据只能从写端被写入,从读端被读出;

1. 管道原理

管道是内核的一块缓冲区,更具体一些,是一个环形队列。数据从队列的一端写入数据,另一端读出,如下图示:

3. 管道的优点

简单

4.  管道的缺点

  • 只能单向通信,如果需要双向通信则需要建立两个管道;
  • 只能应用于具有血缘关系的进程,如父子进程;
  • 缓冲区大小受限,通常为1页,即4k;

二、管道的创建

管道创建三步曲:

  • 父进程调用pipe函数创建管道;
  • 父进程调用fork函数创建子进程;
  • 父进程关闭fd[0],子进程关闭fd[1];

具体如下图所示:

三、管道的读写行为

  • 管道的缓冲区大小固定为4k,所以如果管道内数据已经写满,则无法再写入数据,进程的write调用将阻塞,直到有足够的空间再写入数据;
  • 管道的读动作比写动作要快,数据一旦被读走了,管道将释放相应的空间,以便后续数据的写入。当所有的数据都读完之后,进程的read()调用将阻塞,直到有数据再次写入。

四、例程

父子间通信:

  1. #include <stdio.h> 
  2.  #include <sys/types.h> 
  3.  #include <unistd.h> 
  4.  #include <string.h> 
  5.   
  6.  int main() 
  7.  { 
  8.      int fd[2]; 
  9.      pid_t pid; 
  10.     char buf[1024]; 
  11.     char *data = "hello world!"
  12.  
  13.     /* 创建管道 */ 
  14.     if (pipe(fd) == -1) { 
  15.         printf("ERROR: pipe create failed!\n"); 
  16.         return -1; 
  17.     } 
  18.  
  19.     pid = fork(); 
  20.     if (pid == 0) { 
  21.         /* 子进程 */ 
  22.         close(fd[1]);   // 子进程读取数据,关闭写端 
  23.         read(fd[0], buf, sizeof(buf));  // 从管道读数据 
  24.         printf("child process read: %s\n", buf); 
  25.         close(fd[0]); 
  26.     } else if (pid > 0) { 
  27.         /* 父进程 */ 
  28.         close(fd[0]);   //父进程写数据,关闭读端 
  29.         write(fd[1], data, strlen(data));   // 向管道写数据 
  30.         printf("parent process write: %s\n", data); 
  31.         close(fd[1]); 
  32.     } 
  33.  
  34.     return 0; 

兄弟间通信:

  1.  #include <stdio.h> 
  2.  #include <sys/types.h> 
  3.  #include <unistd.h> 
  4.  #include <string.h> 
  5.  #include <sys/wait.h> 
  6.   
  7.  int main () 
  8.  { 
  9.      int fd[2]; 
  10.     int i = 0
  11.     pid_t pid; 
  12.     char buf[1024]; 
  13.     char *data = "hello world!"
  14.  
  15.     /* 创建管道 */ 
  16.     if (pipe(fd) == -1) { 
  17.         printf("ERROR: pipe create failed!\n"); 
  18.         return -1; 
  19.     } 
  20.  
  21.     for (i = 0; i < 2; i++) { 
  22.         pid = fork(); 
  23.         if (pid == -1) { 
  24.             printf("ERROR: fork error!\n"); 
  25.             return -1; 
  26.         } else if (pid == 0) { 
  27.             break; 
  28.         } 
  29.     } 
  30.  
  31.     /* 通过i来判断创建的子进程及父进程 */ 
  32.     if (i == 0) { 
  33.         /* 第一个子进程,兄进程 */ 
  34.         close(fd[0]);   // 兄进程向弟进程写数据,关闭读端 
  35.         write(fd[1], data, strlen(data)); 
  36.         printf("elder brother send: %s\n", data); 
  37.         close(fd[1]); 
  38.     } else if (i == 1) { 
  39.         /* 第二个子进程,弟进程 */ 
  40.         close(fd[1]); 
  41.         read(fd[0], buf, sizeof(buf)); 
  42.         printf("younger brother receive: %s\n", buf); 
  43.         close(fd[0]); 
  44.     } else { 
  45.         /* 父进程 */ 
  46.         close(fd[0]); 
  47.         close(fd[1]); 
  48.         for (i = 0; i < 2; i++) { 
  49.             wait(NULL); 
  50.         } 
  51.     } 
  52.  
  53.     return 0; 

本文授权转载自公众号「良许Linux」。良许,世界500强外企Linux开发工程师,公众号里分享大量Linux干货,欢迎关注!

 

责任编辑:赵宁宁 来源: 今日头条
相关推荐

2021-02-20 20:36:56

Linux无名管道

2020-10-18 07:13:44

Linux系统编程信号捕捉

2020-09-26 21:43:59

Linux系统编程条件变量

2020-10-05 22:01:02

Linux系统编程线程属性

2020-09-26 23:09:00

Linux系统编程读写锁

2020-09-22 07:35:06

Linux线程进程

2020-09-28 06:49:50

Linux系统编程互斥量mutex

2020-10-05 22:05:10

Linux系统编程时序竞态

2020-09-25 07:34:40

Linux系统编程信号量

2020-10-08 10:10:51

Linux系统编程信号集

2020-10-09 07:13:11

Linux系统编程mmap

2017-02-28 18:26:09

Linuxinput子系统编程

2010-03-05 13:34:54

2019-03-15 09:30:09

Linux系统CPU

2009-07-03 11:57:18

系统编程安全linux

2010-02-02 13:26:53

Linux内核

2009-10-23 16:35:44

linux Debia

2021-05-16 18:02:52

系统编程JavaScript

2018-09-10 08:45:04

Linux管道命令

2013-07-23 10:24:00

点赞
收藏

51CTO技术栈公众号