管道概念
调用pipe函数在内核中开辟一段缓冲区称为管道
函数原型:int pipe(int filedes[2])
返回值:成功–>0;失败–> -1
- 有一个读端(filedes[0])和一个写端(filedes[1])
- 通过filedes参数传出给用户程序两个文件描述符
- 通过read和write函数读写内核缓冲区,进行通信
管道通信图示
父进程关闭读端,子进程关闭写端
- 管道是用环形队列实现的,数据从写端流入从读端流出,就实现了进程间通信
- 管道的生命周期是随进程的
- 管道自带同步机制
- 管道是面向字节流的
- 管道只能单向通信
- 管道通信需要进程间有血缘关系(父子进程)
使用管道的特殊情况
- 写端都关闭,仍然有读端从管道读取数据,剩余数据读完,再次read会返回0
- 写端未关闭也没有向管道写数据,读端仍在读数据,剩余数据读完,再read会阻塞,直到管道中有数据才读取数据并返回
- 读端都关闭,再write,该进程收到SIGPIPE信号,通常导致进程异常终止
- 读端未关闭也没有从管道读数据,写端一直写,当管道写满,再write阻塞,直到管道有空闲位置才写入
利用管道进行进程间通信
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
int main()
{
int pipefd[2] = {0,0};//创建管道
if(pipe(pipefd) < 0){
perror("pipe");
return 1;
}
pid_t id = fork();//创建子进程
if(id < 0){
perror("fork");
return 2;
}else if(id == 0){//child
close(pipefd[0]);//关闭读端
const char *msg = NULL;
int count = 0;
while(count<5)
{
msg = "I am child!";
write(pipefd[1],msg,strlen(msg)+1);//向管道写数据
count++;
sleep(1);
}
}else
{//father
close(pipefd[1]);//关闭写端
char buf[20];
int i = 0;
while(i<5)
{
memset(buf,'\0',sizeof(buf));
read(pipefd[0],buf,sizeof(buf));//从管道读数据
printf("%s\n",buf);
i++;
}
}
return 0;
}