您的位置:首页 > 其它

IPC进程间通信之管道

2015-07-06 10:53 330 查看
管道pipe是UNIX系统IPC进程间通信的最古老形式,并且所有UNIX系统都提供此种通信机制。

管道有下面两种局限性:

1、历史上,管道是半双工管道,数据只能在一个方向上流动,某些系统则提供了全双工管道。

2、管道只能在具有公共祖先的进程之间使用。

半双工管道虽然有自身的局限性,但仍是最常用的IPC形式。每当你在管道线中键入一个由shell执行的命令序列时,shell为每一条命令单独创建一进程,然后将前一条命令进程的标准输出用管道与后一条命令的标准输入相连接。

#include <unistd.h>

int pipe(int pipefd[2]);


管道由pipe函数创建,参数pipefd返回两个文件描述符,pipefd[0]为读而打开,pipefd[1]为写而打开,pipefd[1]的输出是pipefd[0]的输入。

单个进程中的管道几乎没有任何用处,通常调用pipe的进程接着调用fork。对于从父进程到子进程的管道,父进程关闭管道的读端pipefd[0],子进程关闭管道的写端pipefd[1]。当读一个写端已被关闭的管道时,在所有数据都被读取后,read返回0,以指示达到了文件结束处。如果写一个读端已被关闭的管道,则产生SIGPIPE信号。在写管道时,常量PIPE_BUF规定了内核中管道缓冲区的大小,这个需要我们注意。

下面例子说明了管道的简单用法。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void)
{
int n;
int fd[2];
pid_t pid;
char line[4096];

if (pipe(fd) < 0) {
printf("pipe error\n");
return -1;
}

if ((pid = fork()) < 0) {
printf("fork error");
return -1;
}
else if (pid > 0) {
close(fd[0]);
write(fd[1], "pipe from parent\n", 17);
}
else {
close(fd[1]);
n = read(fd[0], line, 4096);
write(STDOUT_FILENO, line, n);
}

exit(0);
}


例子中,从父进程向子进程传送了数据“pipe from parent\n”,子进程又将该数据写到了标准输出。

对于管道,常见的操作是创建一个管道并连接到另一个进程,然后读其输出或向其输入端发送数据,为此标准IO提供了两个函数popen和pclose。这两个函数实现的操作是:创建一个管道,调用fork产生一个子进程,关闭管道不使用的端,执行一个shell以运行命令,然后等待命令终止。函数原型如下:

#include <stdio.h>

FILE *popen(const char *command, const char *type);

int pclose(FILE *stream);


与管道相关有一个重要的概念:协同进程。UNIX系统过滤程序从标准输入读取数据,对其进行适当处理后写到标准输出。几个过滤程序通常在shell管道命令行中线性地连接。当一个程序产生某个过滤程序的输入,同时又读取该过滤程序的输出时,则该过滤程序就成为协同进程。协同进程通常在shell后台运行,其标准输入和标准输出通过管道连接到另一个程序。与popen相比,popen只提供连接到另一个进程的标准输入或标准输出的一个单向管道,而对于协同进程,则它有连接到另一个进程的两个单向管道,一个接到其标准输入,另一个则来自其标准输出。我们先要将数据写到其标准输入,经其处理后,再从其标准输出读取数据。

除了管道,还有FIFO,后者也叫命名管道。普通管道通信的限制是祖先进程相同,而FIFO则不限于此。创建FIFO类似与创建文件:

#include <sys/stat.h>

int mkfifo(const char *path, mode_t mode);


一旦已经用mkfifo创建了一个FIFO,就可用open打开它,其它的文件IO函数close、read、write、unlink都可用于FIFO。

FIFO有下面两种用途:

1、FIFO由shell命令使用以便将数据从一条管道线传送到另一条,为此无需创建中间临时文件。

2、FIFO用于客户进程-服务器进程应用程序中,以在客户进程和服务器进程之间传递数据。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: