概述
管道是最初的Unix 进程间通信(IPC)的方式,它的局限在于没有名字(有名管道FIFO下节讲),从而只能由有亲缘关系的进程间使用,例如父子进程。管道和FIFO都是使用read和write函数访问的。
管道由pipe函数创建,提供一个单向的数据流
#include <unistd.h>
int pipe(int pipefd[2]);
函数返回两个文件描述符,fd[0]和fd[1],0用于读,1用于写。
调用pipe函数会在内核中开辟一块缓存区用于通信,一个读端,一个写端,fd[0]指向读端,fd[1]指向写端。
父子进程如何通过管道实现通信?
1、父进程调用pipe开辟管道,得到两个文件描述符指向管道的两端;
2、父进程调用fork创建子进程,子进程有两个文件描述符指向同一管道;
3、父进程关闭读端,子进程关闭写端。父进程可以往管道里写,子进程可以从管道里读,数据从写端流入,从读端流出,这样就实现了进程间通信。
fork完成之后:
关闭父进程读端、子进程写端,形成半双工(单向)数据流
//
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "errno.h"
#include "string.h"
int main()
{
int _pipe[2];
int ret=pipe(_pipe);
if(ret==-1)//
{
printf("creat pipe error!errno code is:%d\n",errno);
return 1;
}
pid_t id = fork();
if(id<0)
{
printf("fork error!");
return 2;
}
else if(id==0)//child
{
close(_pipe[1]);
char _mesg[100];
int j=0;
while(j<6)
{
memset(_mesg,'\0',sizeof(_mesg));
int res = read(_pipe[0],_mesg,sizeof(_mesg));
printf("%d_%s strlenth is:%d\n",j,_mesg,res);
j++;
}
}
else{//father
close(_pipe[0]);
int i=0;
char* _mesg_c=NULL;
while(i<6)
{
_mesg_c="i im coder";
write(_pipe[1],_mesg_c,strlen(_mesg_c)+1);
sleep(1);
i++;
}
}
return 0;
}
运行结果:
管道通信的四中特殊情况:
1、所有指向管道写端的文件描述符都关闭了,仍有进程从管道的读端读取数据,当管道中剩余的数据都被读取之后,再次读取时会返回0,就像读到文件末尾一样;
2、指向管道写端的文件描述符没关闭,持有管道写端的进程也没有向管道中写数据,这是有进程从管道的读端读取数据,当管道剩余的数据都被读取后,再次读取进程会阻塞,直到管道中有数据可读了才读取数据并返回;
3、如果指向管道读端的文件描述符都关闭了,这是有进程向管道的写端写入数据,该进程会收到SIGPIPE,会导致进程异常终止;
4、如果指向管道读端的文件描述符没关闭,而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,在管道被写满时再次写入会阻塞,直到管道中有空位置了才写入数据并返回。
管道通信的特点:
1、管道是半双工的,只能支持数据的单向流动;两进程间需要通信时需要建立起两个管道;
2、无名管道使用pipe()函数创建,只能用于父子进程或者兄弟进程之间;
3、管道对于通信的两端进程而言,实质上是一种独立的文件,只存在于内存中;
4、数据的读写操作:一个进程向管道中写数据,所写的数据添加在管道缓冲区的尾部;另一个进程在管道中缓冲区的头部读数据。
参考:
http://760470897.blog.51cto.com/10696844/1763616