C语言 在fork中使用pipes()的最佳方式是将fd作为arg传递?

7bsow1i6  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(84)

我试图为我的函数implement a pipe trick,但我有点不知所措 * 如何 *。
这里有一些我正在使用的示例代码-你会得到的想法,因为它是伪代码。

int do_command_exec (fd_t rfd, command_t *command)
pid_t pid; 
fd_t fd;

pid = fork();
if (pid == 0) {
    dup2(rfd, STDIN_FILENO);
    for (fd = 0; fd < NOFILE; fd++) {
        if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO) {
           close(fd);
        }
    }
 }
        memset(cmd, 0, sizeof(cmd));
        memcpy(cmd, command->data, command->len);
        argv[0] = SHELL_CMD;
        argv[1] = "-c";
        argv[2] = cmd;
        argv[3] = NULL;
        execvp(argv[0], argv);
        exit(1);
else
.. parent...

字符串
现在,当我尝试并实现它使用rfd的管道,正如你所期望的,我的程序不正确的功能与STDIN(即:没有日志)

int pipes[2];
    pipe(pipes);
    pid = fork();
    if (pid == 0) /* Child */ 
    close(pipes[1]); 
    dup2(pipes[0], STDIN_FILENO); 
    for (fd = 0; fd < NOFILE; fd++) {
        if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO) {
           close(fd);
        }
    }
 }
        memset(cmd, 0, sizeof(cmd));
        memcpy(cmd, command->data, command->len);
        argv[0] = SHELL_CMD;
        argv[1] = "-c";
        argv[2] = cmd;
        argv[3] = NULL;
        execvp(argv[0], argv);
        exit(1);
else /* Parent */ 
close(pipes[0]);


现在好消息是,我的程序现在像我希望的那样存在(即:可以看到子进程,当父进程因任何原因死亡时,子进程退出,但任何使用STDIN的东西都不再工作)。

xkrw2x1b

xkrw2x1b1#

现在,当我尝试使用rfd为管道实现它时,正如您所期望的,我的程序无法正确使用STDIN(即:没有日志)
每个进程都从其父进程继承其标准输入流。如果您将子进程的标准输入重定向为来自管道,则您最终要控制的子进程,也会将该管道作为其标准输入。它不会从原始程序的标准输入接收输入。您引用的答案不希望被控制的子进程尝试那么做
但有个好消息:shell可以从任意文件描述符中读取数据。答案中给出的示例代码使用其标准输入来监视父文件,这仅仅是一个小小的方便。更好的是,直接执行基本相同的操作,而不涉及shell,这几乎是同样容易的。与问题中给出的伪代码的精神相同,它看起来如下所示:

// parent
    int pipe_fds[2];
    pipe(pipe_fds);
    pid_t monitor_pid = fork();

    // in parent
    ...

    // in child 1 (monitor)
    close(pipe_fds[1]);
    pid_t child_pid = fork();

    // in child 1 (monitor)
    char c;
    read(pipe_fds[0], &c, 1);
    kill(child_pid, SIG_TERM);
    exit(0);

    // in child 2 (child)
    close(pipe_fds[0]);
    execlp("/the/command", "the_command", "arg1", "arg2", (char *) NULL);
    _exit(1);

字符串
当然,真实的的实现需要提供流控制,以使“in parent”、“in child 1”和“in child 2”注解正确,并且它必须实现对返回值和错误处理的正确检查,以及其他操作。

相关问题