【问题标题】:Trying to pass data from execve child process to parent process in C尝试将数据从execve子进程传递到C中的父进程
【发布时间】:2021-01-30 22:02:18
【问题描述】:

我一直在尝试使用管道来传递在子进程中计算的值(由父进程中的 execve 创建),但一直无法弄清楚为什么没有传输数据。我的理解是,除非在管道上设置了 close on exec 标志,否则即使子进程是使用具有新堆栈、堆等的数据副本创建的,管道仍将在进程之间共享?

父进程的工作方式是允许用户输入一个值来更改字符串,并且在子进程中完成字符串重新分配以发送回父进程。

这是我的父进程代码:

if((pid = fork())) {
    if(pid < 0) {
        printf("Fork error: %s\n",strerror(errno));
    }
    wait(&status);
} else {
    int fd[2];
    pipe(fd);
    char* argv[] =  {"new string", variableToChange, NULL};

    ret = execve("newstringchildprocess", argv, environ);
    close(fd[1]);
    int nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
    printf("Received string: %s", readbuffer);
    close(fd[0]);
}

和子进程(单独的C文件):

int fd[2];
pipe(fd);
char readbuffer[100];

close(fd[0]);
printf("Enter new string: ");
write(fd[1], variableToChange, (strlen(variableToChange) + 1));
int charCount = sizeof argv[0];
variableToChange = (char*) malloc(charCount);
close(fd[1]);
wait(NULL);
exit(EXIT_SUCCESS);
       

目前,如果我从两个文件中删除管道代码,我只会从子进程中获得输出。任何帮助都会很棒

【问题讨论】:

  • 你在fork之后调用pipe
  • 除了错误处理之外,exec* 之后没有任何代码。 exec* 除非失败,否则不会返回。

标签: c process pipe parent


【解决方案1】:

如果我理解正确,您需要将孩子的输出连接到父亲。

这样做的一种方法当然是管道,但是您必须在父进程中创建管道然后分叉,因此子进程将继承打开的管道。

哦,如果我没记错的话,在execve 之后,进程“死”了,因为它不会返回到您的代码。

int fd[2];
pipe(fd);
if((pid = fork()) < 0) {
        printf("Fork error: %s\n",strerror(errno));
} else if (pi==0) { //Child process
    char* argv[] =  {"new string", variableToChange, NULL};
    dup2(fd[1],1); //You connect to the pipe in input mode
    execve("newstringchildprocess", argv, environ);
    printf("Shouldn't execute this\n");
    exit(1);

} else{ //Father process
    int nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
    printf("Received string: %s", readbuffer);
    close(fd[0]);
    close(fd[1]);
}

而另一个c文件只需要关注它的逻辑而不是通信:

printf("Enter new string: ");
printf(variableToChange, (strlen(variableToChange) + 1));
int charCount = sizeof argv[0];
variableToChange = (char*) malloc(charCount);
wait(NULL);
exit(EXIT_SUCCESS);

编辑

无论如何,您可以在dup2 中替换您要使用的文件描述符,而不是直接连接到标准输出,它可以连接到另一个 fd 中的管道。这有点难,但会给你更多的灵活性。请记住,在另一个 .c 文件中创建的另一个管道与父管道不同。

int fd[2];
pipe(fd);
if((pid = fork()) < 0) {
        printf("Fork error: %s\n",strerror(errno));
} else if (pi==0) { //Child process
    char* argv[] =  {"new string", variableToChange, NULL};
    execve("newstringchildprocess", argv, environ);
    printf("Shouldn't execute this\n");
    exit(1);

} else{ //Father process
    int nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
    printf("Received string: %s", readbuffer);
    close(fd[0]);
    close(fd[1]);
}

而另一个c文件只需要关注它的逻辑而不是通信:

printf("Enter new string: ");
write(4,variableToChange, (strlen(variableToChange) + 1)); // I put 4 as I assume it is where the input of the pipe is, as i think you can't access fd[1] form this file
int charCount = sizeof argv[0];
variableToChange = (char*) malloc(charCount);
wait(NULL);
exit(EXIT_SUCCESS);

【讨论】:

  • 这是有道理的。但是我应该添加更多上下文,但我正在制作一个 shell,它将在用户输入特定字符串时创建子进程。我将如何将该功能合并到其中,因为似乎子进程 execve 仅在 pid == 1 使用您的示例时才会执行。另外我如何找到管道的输入在哪里,因为我没有将它作为参数传递给子进程?
  • 那很好。我用贝壳做了很多工作。第一个选项适用于外壳。你知道当使用pid=fork() 时,子进程中的pid 为0,而父进程中子进程的pid 为0?这就是让父母简单地等待孩子而孩子简单地执行给定命令的方式。管道的输入位于给定的文件描述符中,正如我在第二个选项(在编辑时)中向您展示的那样。虽然,如果您正在制作 shell,强烈建议使用第一种方法,因为您只需将孩子的输入从管道分配,并将输出直接分配给标准输出
  • 如果您需要更多说明,我可以更广泛地编辑我的答案。不过,如果您发现它有用,请随时投票并接受我的回答为有效。 :)
  • 我已经用更多代码@Román 编辑了我的评论。我正在尝试包含用于输出、输入重定向和退出 shell 的功能,但似乎无论我在 pid==0 条件中添加什么,即使我尝试仅在退出条件中退出的逻辑,shell 也总是退出。 shell处于while循环中,带有任何管道的字符串都被附加到一个链表数据结构中,以便在父进程文件中处理,因为我稍后试图让shell包含管道运算符功能。
  • execveErrorHandler 函数主要只是检查 execve 是否失败并打印带有 strerror 的字符串。感谢您到目前为止的帮助
猜你喜欢
  • 2016-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-03
相关资源
最近更新 更多