Linux系统编程—有名管道

  • A+
所属分类:linux技术
摘要

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

▋****1. 管道的概念

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

1.1 管道本质

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

1.2 管道原理

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

Linux系统编程—有名管道

1.3 管道的优点

简单

1.4 管道的缺点

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

▋****2. 管道的创建

管道创建三步曲:

a. 父进程调用pipe函数创建管道;

b. 父进程调用fork函数创建子进程;

c. 父进程关闭fd[0],子进程关闭fd[1];

具体如下图所示:

Linux系统编程—有名管道

▋****3. 管道的读写行为

a. 管道的缓冲区大小固定为4k,所以如果管道内数据已经写满,则无法再写入数据,进程的write调用将阻塞,直到有足够的空间再写入数据;

b. 管道的读动作比写动作要快,数据一旦被读走了,管道将释放相应的空间,以便后续数据的写入。当所有的数据都读完之后,进程的read()调用将阻塞,直到有数据再次写入。

▋****4. 例程

父子间通信:

 1#include <stdio.h>  2#include <sys/types.h>  3#include <unistd.h>  4#include <string.h>  5  6int 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: %sn", 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: %sn", data); 31        close(fd[1]); 32    } 33 34    return 0; 35} 

兄弟间通信:

 1#include <stdio.h>  2#include <sys/types.h>  3#include <unistd.h>  4#include <string.h>  5#include <sys/wait.h>  6  7int 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: %sn", 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: %sn", 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; 54} 

更多精彩内容,请关注