一、管道概念
管道是最基本的IPC机制,通过管道可以实现父子进程或亲属进程间的通信。在linux中调用pipe函数可以创建一个管道,管道指向内核缓冲区,他有两个端口,分别为读端与写端。写端可以将需要通信的内容写入内核缓冲区,读端则可以将缓冲区的内容读出来。但在进行读写操作时,只能同时进行一种操作,比如在读数据时,写端就需要关闭,这样才能实现正常的读写。
二、管道的创建pipe()
在调用pipe函数后程序将会创建一条管道,管道的读端与写端都将指向新开辟的内存缓冲区,如下图:
这样子一条管道就创建好了。
三、父子进程通信
在父子进程通信时,子进程的读端写端也会指向开辟的那块内存缓冲区,此时若要实现进程间的通信,则需要父进程关闭读端,子进程关闭写端,然后父进程将要发送的内容写入缓冲区,子进程再从缓冲区将信息读出并做出相应的处理,这样就能实现父子进程间的通信了。如下图:
四、代码实现
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#define MAX 80
int main()
{
int n;
int fd[2];
pid_t pid;
char line[MAX];
if(pipe(fd)<0)
perror("pipe");
if((pid=fork())<0)
perror("fork");
if(pid>0)
{
close(fd[0]);
write(fd[1],"Hello World\n",12);
wait(NULL);
}
else
{
close(fd[1]);
n=read(fd[0],line,MAX);
write(STDOUT_FILENO,line,n);
}
return 0;
}
五、使用管道应注意:
1、当所有的写端的文件描述符都已经关闭了,但此时依然有进程从独断读数据,当管道中的数据被读完时再次进行读的话,将会返回0,类似于读到文件的末尾。
2、当有写端文件描述符没有关闭,而写端进程又没有向管道写数据,此时若有进程去读数据则会造成进程阻塞,直到写端写入了数据。
3、当所有读端都文件描述符已经关闭,此时有进程依然向写端写入数据,此时该进程将收到SIGPIPE信号,将会异常终止。
4、当有写端文件描述符没有关闭,当持有写端的进程向管道写入数据,此时读端进程并没有进行读操作,当管道写满后,写端进程将被阻塞,直到读端进程读取数据使写端有足够空间可以写入时再进行。
六、命名管道
在这之前我们讲到的管道都属于匿名管道,而匿名管道在进行进程间通信时只能实现父子进程间的通信,既然提到了匿名管道,自然也就有命名管道,与匿名管道不同,命名管道可以实现两个不相关进程间的通信。
匿名管道是通过开辟一个内存缓冲区使两个进程进行数据的读取,而命名管道是通过两个进程共同打开一个真实存在的文件来实现通信的,因此命名管道可以实现两个不相关进程间的通信。