举例:stream pipe使用
这里对前面的协作处理程序使用单个的streams pipe做了一个重新的实现。下面的代码给出了新的main函数,而add2协作处理程序和前面的一样。我们调用了一个新的函数s_pipe来创建一个单一的streams pipe(我们马上会给出这个函数的stream pipes和unix domain sockets两种实现)。
通过streams pipe来调用add2程序的例子
#include "apue.h"
static void sig_pipe(int); /* our signal handler */
int main(void)
{
int n;
int fd[2];
pid_t pid;
char line[MAXLINE];
if (signal(SIGPIPE, sig_pipe) == SIG_ERR)
err_sys("signal error");
if (s_pipe(fd) < 0) /* need only a single stream pipe */
err_sys("pipe error");
if ((pid = fork()) < 0) {
err_sys("fork error");
} else if (pid > 0) { /* parent */
close(fd[1]);
while (fgets(line, MAXLINE, stdin) != NULL) {
n = strlen(line);
if (write(fd[0], line, n) != n)
err_sys("write error to pipe");
if ((n = read(fd[0], line, MAXLINE)) < 0)
err_sys("read error from pipe");
if (n == 0) {
err_msg("child closed pipe");
break;
}
line[n] = 0; /* null terminate */
if (fputs(line, stdout) == EOF)
err_sys("fputs error");
}
if (ferror(stdin))
err_sys("fgets error on stdin");
exit(0);
} else { /* child */
close(fd[0]);
if (fd[1] != STDIN_FILENO &&
dup2(fd[1], STDIN_FILENO) != STDIN_FILENO)
err_sys("dup2 error to stdin");
if (fd[1] != STDOUT_FILENO &&
dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO)
err_sys("dup2 error to stdout");
if (execl("./add2", "add2", (char *)0) < 0)
err_sys("execl error");
}
exit(0);
}
static void sig_pipe(int signo)
{
printf("SIGPIPE caught\n");
exit(1);
}
父进程只使用 fd[0]
进行读写(向 fd[0]
写的内容反应到 fd[1]
的读取中,从 fd[0]
读取的内容来自 fd[1]
的写入),子进程只使用 fd[1]
进行读写。因为streams pipe的每个末端都是全双工的,所以父进程只是读取和写入 fd[0]
;子进程将标准输入输出复制到 fd[1]
,达到对 fd[1]
进行读写的目的(之前是使用了两个半双工管道对应两对文件描述符号,这里只使用一个管道对应一对文件描述符号)。下面的图就展示了结果文件描述符号的情况。注意这里的例子也可以使用不基于流的全双关工的pipes来实现,因为这个例子没有使用任何关于流的特性。
前面说过FreeBSD支持全双工pipes,但是这样的pipes不是基于流机制的。
协作处理程序中的文件描述符号布局
Parent Child(coprocess)
+----------+ +--------------+
| | /--------------->| stdin |
| fd[0] <-------|---------------->| fd[1] |
| | \--------------->| stdout |
+----------+ +--------------+
我们定义的s_pipe和标准的pipe函数类似。两个函数使用接收同样的参数,但是s_pipe返回的文件描述符号以读和写的方式打开。
网友评论