定义
管道是最古老的IPC方法,进程之间通过读写管道的fd进行通信。
性质
- 只有当所有的写入端fd都已经关闭,且管道中的数据都已经被读出,这时对读取端fd调用read函数才会返回0,也就是读到了EOF标识。
- 当所有的读取端fd都已经关闭,再向该管道写入数据时,写操作会失败,errno全局变量置为EPIPE,与此同时内核会向写入进程发送一个SIGPIPE的信号。
- 当所有的读取端fd和写入端fd都关闭以后,管道才能被销毁。
管道本质是一片内存区域,写入端通过fd[1]将数据写入这片内存,读取端通过fd[0]从这片内存读走数据。
使用场景
正常使用管道的场景,应该是关闭其它多余的管道文件描述符,只留两个进程和管道相关联,一个进程拥有管道的读取端,另一个进程拥有管道的写入端,实现一个进程写,另一个进程读的通信效果。
接口
创建管道:
#include <unistd.h>
int pipe(int pipefd[2]);
pipfd[2],管道的fd数组,pipefd[0]对应管道读取端,pipefd[1]对应管道的写入端
#include <fcntl.h>
#include <unistd.h>
int pipe2(int pipefd[2], int flags);
- 当flag为0时,pipe2()与pipe()功能完全一样
- 当flag为O_CLOEXEC时,返回的pipefd[0]、pipefd[1]都带有FD_CLOEXEC属性
- 当flag为O_NONBLOCK时,返回的pipefd[0]、pipefd[1]都带有O_NONBLOCK不阻塞属性
返回值:成功返回0,失败返回-1,可通过全局变量errno判断失败的原因
例子
创建一个管道,然后fork一个新的进程,让父进程和子进程通过管道进行通信
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<string.h>
int main(int argv, char *argc[])
{
int pipe_fd[2];
char buf[100];
memset(buf,0,100);
//创建管道
if(pipe(pipe_fd)<0)
{
printf("creat pipe error.\n");
}
switch(fork())
{
case 0:
//子进程,向管道写入数据
close(pipe_fd[0]);
write(pipe_fd[1],"hello,father.\n",15);
printf("[child]send str:hello,father.\n");
sleep(10);
close(pipe_fd[1]);
break;
default:
//父进程,从管道读取数据
close(pipe_fd[1]);
while(read(pipe_fd[0],buf,100))
{
printf("[parent]recv str:%s\n",buf);
}
printf("child had closed pipefd.\n");
close(pipe_fd[0]);
break;
}
while(1);
}
运行结果:
./a.out
[child]send str:hello,father.
[parent]recv str:hello,father.