gpt4 book ai didi

c - 了解管道、重定向和 IPC

转载 作者:太空狗 更新时间:2023-10-29 12:29:08 26 4
gpt4 key购买 nike

我是管道的新手,一直在尝试创建一对管道,它允许子进程写入父进程,并让父进程返回通信。有 1 位家长最多带 4 个 child 。 child 变成了exec不同的程序。

我的工作:

从父进程写入子进程。当我读入子程序的标准输入时,它会收到我从父程序中写入的内容。

目标:

创建一个纸牌游戏,父进程与每个单独的客户端(子进程)交谈,并向他们提供所有 Action 和信息,从其标准输出到子进程的标准输入。各个子进程在其 stdout 上返回它们的移动,由主要父进程读取。游戏的 Action 完全由顺序决定,而不是玩家。所以这是一个机器人游戏。

我坚持的是:

我不确定如何获取它以便 parent 可以通过文件流读取 child 的标准输出。当我尝试设置从子行读取时,代码似乎停止工作。甚至 child 也不能从 parent 那里读取(它似乎停止在现在被注释掉的用于设置 child 到 parent 的留置权)。

我也不确定如何“等待”直到某些东西出现。比如,一开始玩家必须向 parent 发送一条“准备就绪”消息,让他们知道他们正在工作。一旦我从 child 发送“准备好”,我如何无限期地“等待”直到下一条消息出现?

我不确定我是否正确设置了管道。有人可以提供有关如何使用通信管道的指导并确认我在下面的逻辑吗?

我收集到的让 parent 写给 child 的是:

  1. 首先创建管道
  2. 将父进程 fork 到另一个进程(子进程)
  3. 将管道的输入连接到父级的标准输出,并使用 dup2 关闭父级的读取端并关闭
  4. 将管道的输出连接到 child 的标准输入,并使用 dup2 关闭 child 的书写部分并关闭
  5. 使用 fdopen() 从文件描述符获取文件流,然后打印到该文件流。
  6. 子进程标准输入现在是您从父进程打印到标准输出的任何内容。

这是正确的吗?我尝试将这种针对 child 的逻辑应用于 parent ,但将其颠倒过来。

  1. 将输入管道连接到读取文件流,这是子程序从其标准输出写入的地方。
  2. 将输出管道连接到父级读取的读取流。

    void start_child_process(Game *game, int position) {
    int child2Parent[2];
    int parent2Child[2];

    if (pipe(parent2Child)) {
    printf("PIPE FAIL!\n");
    }
    if (pipe(child2Parent)) {
    printf("PIPE FAIL!\n");
    }

    pid_t pid = fork();
    game->readStream[position] = fdopen(child2Parent[0], "r");
    game->writeStream[position] = fdopen(parent2Child[1], "w");

    if (pid) { // Parent
    // Write from parent to child
    close(parent2Child[0]);
    dup2(fileno(game->writeStream[position]), STDOUT_FILENO);
    fprintf(game->writeStream[position], "%s", "test message");
    fflush(game->writeStream[position]);
    close(parent2Child[1]);

    // Read from child -- not working

    /*dup2(child2Parent[0], STDIN_FILENO);
    close(child2Parent[0]);
    close(child2Parent[1]);
    */

    } else {
    // Setup child to read from stdin from parent
    dup2(parent2Child[0], STDIN_FILENO);
    close(parent2Child[1]);

    // Setup writing from child to parent

    /*
    if (dup2(child2Parent[1], STDOUT_FILENO) == -1) {
    fprintf(stderr, "dup2 in child failed\n");
    } else {
    fprintf(stderr, "dup2 in child successful\n");
    close(child2Parent[0]);
    close(child2Parent[1]);
    }
    */


    if ((int)execl("child", "2", "A", NULL) == -1) {
    printf("Failed child process\n");
    }

    }
    }

我的 child 主要有以下内容:

char string[100];
printf("reading from pipe: %s\n", fgets(string, 100, stdin));

但是我不知道怎么办

此外,我不允许使用 popen() 或 write()。显然我也被鼓励使用文件流。

最佳答案

我主要针对您在父进程和子进程之间建立双向通信的主要问题发言。如果您需要其他答案,请提出单独的问题。

你似乎有一个合理的通用方法,但你确实有一个严重的误解/设计缺陷:虽然多个客户端将它们的标准流连接到管道以与父进程通信是合理的,但你不能连接父进程的如果您希望一次能够处理多个客户端,则将所有这些管道结束到父级的标准流。毕竟,父级只有一组标准流。为了支持多个客户端,父进程必须为每个客户端维护一对单独的文件描述符和/或流,并且必须通过这些而不是通过其标准流进行通信。

我不确定为什么当你连接子到父方向时你的父/子通信失败。该过程确实类似于设置另一个端点。这是一个工作示例:


父类.c:

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

int main() {
int child2Parent[2];
int parent2Child[2];
char buffer[256];
FILE *p2cStream;
FILE *c2pStream;
pid_t pid;

if (pipe(parent2Child) || pipe(child2Parent)) {
perror("Failed to create pipes");
exit(EXIT_FAILURE);
}

switch (pid = fork()) {
case -1: /* error */
perror("Failed to fork");
break;
case 0: /* child */
// Setup child to read from stdin from parent
close(parent2Child[1]); /* ignoring any error */
close(child2Parent[0]); /* ignoring any error */
if ((dup2(parent2Child[0], STDIN_FILENO) < 0)
|| (dup2(child2Parent[1], STDOUT_FILENO) < 0)) {
perror("Failed to duplicate file descriptors");
} else {
/* conventionally, the first program argument is the program name */
/* also, execl() returns only if it fails */
execl("child", "child", "2", "A", NULL);
perror("Failed to exec child process");
}

exit(EXIT_FAILURE);
break;
default: /* parent */
close(parent2Child[0]); /* ignoring any error */
close(child2Parent[1]); /* ignoring any error */
if (!(p2cStream = fdopen(parent2Child[1], "w"))
|| !(c2pStream = fdopen(child2Parent[0], "r"))) {
perror("Failed to open streams");
exit(EXIT_FAILURE);
}
if ((fprintf(p2cStream, "test message from parent\n") < 0)
|| fclose(p2cStream)) {
perror("Failed to write to the child");
exit(EXIT_FAILURE);
}
if (fscanf(c2pStream, "%255[^\n]", buffer) < 1) {
perror("Failed to read the child's message");
exit(EXIT_FAILURE);
}
printf("The child responds: '%s'\n", buffer); /* ignoring any error */
break;
}

return EXIT_SUCCESS;
}

child .c:

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

int main(int argc, char *argv[]) {
char buffer[256] = { 0 };

if (scanf("%255[^\n]", buffer) < 0) {
perror("Failed to reading input");
exit(EXIT_FAILURE);
}

/*
* If stdout is connected to the parent then we must avoid
* writing anything unexpected to it
*/
if (fprintf(stderr, "received: '%s'\n", buffer) < 0) {
perror("Failed to echo input");
exit(EXIT_FAILURE);
}

printf("Hi, Mom!\n"); /* ignoring any error */
fflush(stdout); /* ignoring any error */

return EXIT_SUCCESS;
}

对比你的代码,请注意

  • 注意检查所有可能表示我关心的错误的返回值;
  • parent 使用标准流以外的流与 child 进行通信(尽管只有一个 child ,这是一种便利而非必要);
  • execl() 参数的约定。

另请注意,对于等待某物“出现”而言,以这种方式设置的 IPC 流上的 I/O 操作将自动产生该效果。然而,您如何能够或应该如何利用它肯定是一个不同的问题。

关于c - 了解管道、重定向和 IPC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32823609/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com