什么是匿名管道
管道是用于进程间通信的机制。管道是半双工的,某些系统上的管道是全双工的,但是为了更好的移植性,应把管道当作是半双工的。管道可以分为
匿名管道
和命名管道(FIFO)
,其中匿名管道是在具有共同祖先的两个进程中使用,通常是在父进程中fork()子进程,在父进程和子进程中通信。
创建匿名管道
#include <unistd.h>
int pipe(int pipefd[2]);
参数
- pipefd : 用于返回两个文件描述符
- pipefd[0] : 管道读出端
- pipefd[1] : 管道写入端
通常情况下,我们在一个进程使用pipe函数创建一个管道,如下图:
然后,我们使用fork创建一个进程,由于子进程继承了父进程的文件资源,所以,子进程也拥有了管道。这时,因为一个管道只能做单向的通信,所以,我们可以手动将各端的一个文件描述符(一端为只读,另一端为只写)close掉。如下图:
使用匿名管道
管道使用read和write函数,采用字节流的方式,具有流动性,每读一段数据,管道内会清除已读出的数据。
- 读数据时,若管道为空,则被阻塞,直到管道另一端write为止,若写端关闭,则返回0
- 写数据时,若管道满,则被阻塞,直到管道另一端read为止
用close函数,在创建管道时,写端需要关闭pipefd[0],读端需要关闭pipefd[1]。当进程关闭时,需要将写端和读端的文件描述符都关闭。
示例
//pipe_test.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MAX_BUF_LEN 128
int main()
{
int pipe_fd[2]={0},ret=0;
char buf[MAX_BUF_LEN+1] = {0};
const char* testBuf = "Message sent by parent process to child process";
if(pipe(pipe_fd) != 0)
{
perror("pipe error!\n");
exit(-1);
}
if(fork()==0)
{
close(pipe_fd[1]);
ret = read(pipe_fd[0],buf,MAX_BUF_LEN - 1);
buf[ret] = 0;
printf("Message read by child process : %s\n",buf);
close(pipe_fd[0]);
}
else
{
close(pipe_fd[0]);
ret = write(pipe_fd[1],testBuf,strlen(testBuf));
ret = wait(NULL);
close(pipe_fd[1]);
}
return 0;
}