|
LInux中pipe只能支持单向通道,而popen实际上就是将(pipe,fork,exec)这三步简化成一步,但是我一开始产生了一个误区,问题在协同进程这,我们都知道,协同进程可以用两个单向管道来构造,我一开始认为用两个popen也可以达到同样的功能,但在理论上这是行不通的,因为,用两个pipe的方法只创建一个子进程(协同进程);而用两次popen会产生两个子进程(两次fork),所以这两种方法的区别应该如下图:
所以说按道理popen的方法是应该不能起到协同进程的作用的,可是结果呢,它同样能很好的运行,下面是两种方法的代码,用过滤程序的功能是从输入得到两个整数,然后输出二者之和:
方法1:pipe
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <signal.h>
- #include <fcntl.h>
- #define MAX_LINE 2048
- static void sig_pipe(int);
- int
- main(void)
- {
- int n, fd1[2], fd2[2];
- char line[MAX_LINE];
- pid_t pid;
-
- if (signal(SIGPIPE, sig_pipe) == SIG_ERR) {
- printf("init signal error: %s\n", strerror(errno));
- exit(1);
- }
-
- if ((pipe(fd1) < 0) || (pipe(fd2) < 0)) {
- printf("create pipe error: %s\n", strerror(errno));
- exit(1);
- }
-
- if ((pid = fork()) < 0) {
- printf("fork error: %s\n", strerror(errno));
- exit(1);
- } else if (pid > 0) {
- close(fd1[0]);
- close(fd2[1]);
- while (fgets(line, MAX_LINE, stdin) != NULL) {
- n = strlen(line);
- if (write(fd1[1], line, n) != n) {
- printf("write to pipe failed: %s\n", strerror(errno));
- exit(1);
- }
-
- if ((n = read(fd2[0], line, MAX_LINE)) < 0) {
- printf("read from pipe failed: %s\n", strerror(errno));
- exit(1);
- }
-
- if (n == 0) {
- printf("child closed pipe\n");
- break;
- }
-
- line[n] = 0;
- if (fputs(line, stdout) == EOF) {
- printf("fputs error: %s\n", strerror(errno));
- exit(1);
- }
- }
- if (ferror(stdin)) {
- printf("fgets error: %s\n", strerror(errno));
- exit(1);
- }
- } else {
- close(fd1[1]);
- close(fd2[0]);
-
- if (fd1[0] != STDIN_FILENO) {
- if (dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO) {
- printf("dup2 error: %s\n", strerror(errno));
- exit(1);
- }
- close(fd1[0]);
- }
-
- if (fd2[1] != STDOUT_FILENO) {
- if (dup2(fd2[1], STDOUT_FILENO) != STDOUT_FILENO) {
- printf("dup2 error: %s\n", strerror(errno));
- exit(1);
- }
- close(fd2[1]);
- }
-
- if (execl("./add2", "add2", (char *)0) < 0) {
- printf("execl error: %s\n", strerror(errno));
- exit(1);
- }
- }
-
- exit(0);
- }
- static void
- sig_pipe(int signo)
- {
- printf("SIG_PIPE caught\n");
- exit(1);
- }
复制代码
方法2:popen
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <signal.h>
- #include <fcntl.h>
- #define MAX_LINE 2048
- static void sig_pipe(int);
- int
- main(void)
- {
- int n, fd[2];
- char line[MAX_LINE];
- pid_t pid;
- FILE *fpin, *fpout;
-
- if (signal(SIGPIPE, sig_pipe) == SIG_ERR) {
- printf("init signal error: %s\n", strerror(errno));
- exit(1);
- }
-
- if ((fpout = popen("./add2", "w")) == NULL) {
- printf("popen error: %s\n", strerror(errno));
- exit(1);
- }
-
- if ((fpin = popen("./add2", "r")) == NULL) {
- printf("popen error: %s\n", strerror(errno));
- exit(1);
- }
-
- while (fgets(line, MAX_LINE, stdin) != NULL) {
- n = strlen(line);
- fd[0] = fileno(fpout);
- if (write(fd[0], line, n) != n) {
- printf("write to pipe failed: %s\n", strerror(errno));
- exit(1);
- }
- fd[1] = fileno(fpin);
- if ((n = read(fd[1], line, MAX_LINE)) < 0) {
- printf("read from pipe failed: %s\n", strerror(errno));
- exit(1);
- } else if (n == 0) {
- printf("child closed pipe\n");
- break;
- } else {
- line[n] = 0;
- if (fputs(line, stdout) == EOF) {
- printf("fputs error: %s\n", strerror(errno));
- exit(1);
- }
- }
- }
- if (ferror(stdin)) {
- printf("fgets error: %s\n", strerror(errno));
- exit(1);
- }
- exit(0);
- }
- static void
- sig_pipe(int signo)
- {
- printf("SIG_PIPE caught\n");
- exit(1);
- }
复制代码
过滤程序:
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <errno.h>
- #define MAX_LINE 2048
- int
- main(void)
- {
- int n, int1, int2;
- char line[MAX_LINE];
-
- while ((n = read(STDIN_FILENO, line, MAX_LINE)) > 0) {
- if (sscanf(line, "%d%d", &int1, &int2) == 2) {
- sprintf(line, "%d\n", int1 + int2);
- n = strlen(line);
- if (write(STDOUT_FILENO, line, n) != n) {
- printf("write error: %s", strerror(errno));
- exit(1);
- }
- } else {
- if (write(STDOUT_FILENO, "Invalid args\n", 13) != 13) {
- printf("write error: %s", strerror(errno));
- exit(1);
- }
- }
- }
- exit(0);
- }
复制代码
这两种方法都可以运行,效果一样,而且在用popen方法的时候,ps一下会看到确实有两个add2子进程,现在问题出来了,为什么popen这种方法也能正常工作呢,小弟刚开始学unix编程不久,还请各位兄弟多来发表一下自己的看法 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
|