【问题标题】:C - Pipe input from one program to another programC - 将输入从一个程序传送到另一个程序
【发布时间】:2017-11-07 04:55:06
【问题描述】:

我应该创建两个程序(main 和 aux),其中 main 派生一个子程序来执行 aux。父级从用户那里获取输入,直到空行'\n',然后子级执行 aux,这应该将输入打印回来。我能够使用注释代码而不是 execlp() 让它在 main 中工作,但不能让 execlp(aux) 正常工作。任何帮助表示赞赏。

“main.c”

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

int main() {
    int fd[2], i;
    char line[100], buffer[100];

    pipe(fd);

    pid_t pid = fork();

    if (pid < 0) {
            printf("Fork Failed\n");
            exit(-1);
    }
    else if (pid > 0) {
            close(fd[0]);
            while(fgets(line, sizeof(line), stdin) && line[0] != '\n') {
                    write(fd[1], line, sizeof(line));
            }
            close(fd[1]);
    }
    else {
            close(fd[1]);
            dup2(fd[0], STDIN_FILENO);

            //while(read(fd[0], buffer, sizeof(buffer)))
            //      printf("> %s", buffer);

            execlp("./aux", "aux", (char *)0);
    }
    return 0;
}

“aux.c”

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

int main() {
    char data[100];

    while(fgets(data, sizeof(data), stdin))
            printf(">%s\n", data);

    return 0;
}

样本输入/输出

this
>this

is a test
>
> test

only prints larger text with random \n
>
>ts larger text with random \n

【问题讨论】:

  • 嗨,您正在执行一个带有 exec*() 系列的新图像,它完全替换了原始图像。比如程序文本、堆、栈等。
  • 阅读ALP 和像execve(2) 这样的手册页
  • 编译所有警告和调试信息:gcc -Wall -Wextra -g 然后使用调试器gdbstrace(1)。添加调试printf。检查execlp 是否失败(例如,使用perror("execlp"); ....)
  • 您应该在将fd[0] 复制到标准输入后将其关闭。这一次,你侥幸逃脱;你不会总是这样做的。
  • 谢谢,伙计们。我能够通过用 strlen(line) 替换 sizeof(line) 来使其工作。我还在你们提到的地方添加了 perror 和 close(fd[0])。

标签: c pipe fork


【解决方案1】:

你对write(2) 的调用是错误的(你总是write 100 字节,即使是更短的line-s):

                write(fd[1], line, sizeof(line)); // WRONG

应该使用strlen(3)

            size_t ll = strlen(line);
            ssize_t wc = write(fd[1], line, ll);
            if (wc != ll)
              fprintf(stderr, "write was wrong (only %d, wanted %d) - %s\n",
                      (int) wc, (int) ll, strerror(errno));

由于您只想写入 line 缓冲区的填充字节,因此并非每次都写入 100 个字节(其中一些未初始化)。

在您的情况下,sizeof(data) 是 100,因为您声明了 char data[100];

请仔细阅读每个使用函数的文档(以及ALP 或其他有关 Unix/POSIX/Linux 编程的书籍)。 strerror(3)errno(3) 的文档告诉您需要添加:

  #include <string.h>
  #include <errno.h>

实际上,如果您想直接使用read(2)write(2)(不使用stdio(3)),您应该更喜欢使用更大的缓冲区(例如,每个至少4Kbytes 以提高效率)并且您需要管理部分read-s和write-s 自己做缓冲。

顺便说一句,使用所有警告和调试信息进行编译:gcc -Wall -Wextra -g 并学习 use the gdb debuggerstrace(1)(和 valgrind)。一般来说,是undefined behaviorscared(不过,乍一看,你的程序似乎没有UB)。

注意execlp(3) 可能会失败。考虑在它之后添加一些对perror(3) 的调用。

【讨论】:

  • 谢谢! strlen 把它修好了。我还输入了您、Basile Starynkevitch 和 Jonathan Leffler 提到的错误检查代码。这是我上的第一堂 C 课,教授从来没有使用过 gdb 调试器。我一定会调查的。再次感谢大家。
  • 你肯定需要学习如何使用gdb。它的文档有一个很好的教程页面。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-08
  • 2015-12-16
  • 1970-01-01
  • 2019-10-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多