【问题标题】:Using two pipes to communicate between parent process and child process使用两个管道在父进程和子进程之间进行通信
【发布时间】:2020-02-06 22:59:17
【问题描述】:

问题

我只在终端输出中得到这个。我相信该程序在fork() 调用时卡住了,但我不知道具体原因。

程序名称是q9:

prompt>$ ./q9 inputString
Parent: writing to pipe 'inputString'

任务

  • 从终端读取输入到父子管道。
  • fork() 创建子进程。
  • 从父子管道读取输入。
  • 将一些其他字符串连接到从管道读取的字符串。
  • 将新连接的字符串写入子到父管道。
  • 在父级中,从子级到父级管道读取,并将从管道读取的输出打印到终端。

尝试

我已尝试通过以下方式解决此问题:

  • 正在尝试关闭不同位置的管道。我以为我可能遗漏了一些东西或留下了一些东西,但我不这么认为。
  • 在父级中放置一个 wait(),因为它可能没有让子级完全运行
  • 尝试打印连接字符串的输出,以防万一打印结果混乱。

代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>

int main (int argc, char *argv[]) {
    // parent RUN
    if(argc == 1) {
        printf("usage: q9 <string>\n");
        return 0;
    }

    // create two way pipes
    int parent_fds[2], child_fds[2];

    // create strings to save too
    char fromParent[100];
    char fromChild[100];

    // read:[0] - write:[1]
    if (pipe(parent_fds) != 0 && pipe(child_fds) != 0) {
        fprintf(stderr, "pipes failed!\n");
    }

    // close unused pipe end by parent
    close(parent_fds[0]);
    close(child_fds[1]);
    close(child_fds[0]);

    // write from terminal to parent pipe FOR child to read
    printf("Parent: writing to pipe '%s'\n", argv[1]);
    write(parent_fds[1], argv[1], strlen(argv[1]));
    close(parent_fds[1]);

    // fork() child process
    int child = fork();

    // NEVER GETS PASSED HERE :(

    if (child < 0) {
        fprintf(stderr, "fork failed!");
        exit(1);
    } else if (child == 0) {
        printf("I reached the child :)");
        // close unwanted pipe ends by child
        close(child_fds[0]);
        close(parent_fds[1]);

        // read from parent pipe
        int n = read(parent_fds[0], fromParent, 100);
        fromParent[n] = 0;
        printf("Child: reading from parent pipe '%s'\n", fromParent);
        close(parent_fds[0]);

        // Concatinate to what was read in
        const char myText[14] = " (added this.)";
        strcat(fromParent, myText);

        write(child_fds[1], fromParent, strlen(fromParent));
        close(child_fds[1]);
        printf("Child: writing to pipe - '%s'\n", fromParent);
    } else {
        // read from child pipe
        int n = read(child_fds[0], fromChild, 100);
        fromChild[n] = 0;
        printf("Parent: reading from pipe - '%s'\n", fromChild);
    }

    return 0;
}

出了什么问题?

【问题讨论】:

  • 您的管道操作顺序不正确。你需要先fork。然后分别进行父子close 调用,然后分别调用readwrite
  • 调试的时候最好写信给stderr。当您写信给stdout(特别是;也写给stderr)时,请确保以换行符结束消息。考虑使用fflush(stdout); 以确保输出可见。在输出中包含 PID 编号 - 在打印调用中使用 getpid() 以确保您不会在 fork() 调用中获得过时的值。

标签: c pipe fork wait


【解决方案1】:

有几个问题,您的诊断消息不能保证会出现。确保以换行符结束消息。

  1. 您只创建了一个管道,因为您使用了&amp;&amp; 而不是||
  2. 您在创建子代之前“为父代”关闭了管道(kaylumcomment 中也注明了这一点)。

下面的代码中有多个其他清理。代码(仍然)不能确保写入管道操作成功(它们之前失败)。它确实确保从管道读取的字符串不长于放置它们的缓冲区;它不能确保有足够的空间在孩子中附加额外的信息。显示的代码在退出之前等待任何子进程完成。孩子执行wait() 调用但它立即失败(并且孩子不打印任何东西)并退出。父母等待孩子完成并在退出之前报告它这样做。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    if (argc == 1)
    {
        fprintf(stderr, "Usage: %s <string>\n", argv[0]);
        return EXIT_FAILURE;
    }

    // create two pipes:
    // - parent_fds used by parent to write to child
    // - child_fds used by child to write to parent
    int parent_fds[2], child_fds[2];

    // read:[0] - write:[1]
    if (pipe(parent_fds) != 0 || pipe(child_fds) != 0)  /* || not && */
    {
        fprintf(stderr, "pipes failed!\n");
        return EXIT_FAILURE;
    }

    // fork() child process
    int child = fork();

    if (child < 0)
    {
        fprintf(stderr, "fork failed!");
        return EXIT_FAILURE;
    }
    else if (child == 0)
    {
        printf("%d: I reached the child :)\n", (int)getpid());
        // close unwanted pipe ends by child
        close(child_fds[0]);
        close(parent_fds[1]);

        // read from parent pipe
        char fromParent[100];
        int n = read(parent_fds[0], fromParent, sizeof(fromParent) - 1);
        fromParent[n] = '\0';
        printf("%d: Child: read from parent pipe '%s'\n", (int)getpid(), fromParent);
        close(parent_fds[0]);

        // Append to what was read in
        strcat(fromParent, " (added this.)");

        write(child_fds[1], fromParent, strlen(fromParent));
        close(child_fds[1]);
        printf("%d: Child: writing to pipe - '%s'\n", (int)getpid(), fromParent);
    }
    else
    {
        // close unwanted pipe ends by parent
        close(parent_fds[0]);
        close(child_fds[1]);

        // write from terminal to parent pipe FOR child to read
        printf("%d: Parent: writing to pipe '%s'\n", (int)getpid(), argv[1]);
        write(parent_fds[1], argv[1], strlen(argv[1]));
        close(parent_fds[1]);
        // read from child pipe
        char fromChild[100];
        int n = read(child_fds[0], fromChild, sizeof(fromChild) - 1);
        fromChild[n] = '\0';
        close(child_fds[0]);
        printf("%d: Parent: read from pipe - '%s'\n", (int)getpid(), fromChild);
    }

    int corpse;
    int status;
    while ((corpse = wait(&status)) > 0)
        printf("%d: child PID %d exited with status 0x%.4X\n", (int)getpid(), corpse, status);

    return EXIT_SUCCESS;
}

示例输出(源pipe43.c,程序pipe43):

$ pipe43 'Nobody expects the Spanish Inquisition!'
84543: Parent: writing to pipe 'Nobody expects the Spanish Inquisition!'
84544: I reached the child :)
84544: Child: read from parent pipe 'Nobody expects the Spanish Inquisition!'
84544: Child: writing to pipe - 'Nobody expects the Spanish Inquisition! (added this.)'
84543: Parent: read from pipe - 'Nobody expects the Spanish Inquisition! (added this.)'
84543: child PID 84544 exited with status 0x0000
$

【讨论】:

  • 我以为我已经对此发表了评论。但是以防万一它被删除或我想说谢谢。在通读并测试它并修改代码之后,我明白了它是如何工作的。此外,我去更多的办公时间,现在这个概念对我来说更有意义,我能够完成所有事情。虽然迟交,但他感谢我花时间调查并了解它的实际工作原理。我喜欢高端的计算机科学课程,因为他们掌握了学习过程。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-16
  • 1970-01-01
  • 1970-01-01
  • 2019-02-27
  • 2011-12-22
  • 2020-04-09
  • 2015-09-27
相关资源
最近更新 更多