Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
了解管道、重定向和IPC_C_Linux_Pipe - Fatal编程技术网

了解管道、重定向和IPC

了解管道、重定向和IPC,c,linux,pipe,C,Linux,Pipe,我是管道新手,一直在尝试创建一对管道,允许子进程写入父进程,父进程返回通信。一位家长最多有4个孩子。使用exec,子程序将变成不同的程序 我的工作内容: 从父进程写入子进程。当我读入子程序的stdin时,它将收到我从父程序写入的内容 目标: 创建一个纸牌游戏,其中家长与每个单独的客户(子进程)交谈,并向他们提供所有的动作和信息,从其stdout到孩子的stdin。单个子进程在其标准输出上返回其移动,由主父进程读取。游戏的动作完全由一个序列决定,而不是由玩家决定。所以这是一个机器人游戏 我的困境:

我是管道新手,一直在尝试创建一对管道,允许子进程写入父进程,父进程返回通信。一位家长最多有4个孩子。使用exec,子程序将变成不同的程序

我的工作内容:

从父进程写入子进程。当我读入子程序的stdin时,它将收到我从父程序写入的内容

目标:

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

我的困境:

我不知道如何获取它,以便家长可以通过文件流读取孩子的标准输出。当我试图设置从子行读取时,代码似乎停止工作。甚至孩子也不能从父母那里读东西(它似乎停止在现在注释掉的用于设置孩子到父母的留置权上)

我也不知道如何“等待”直到有东西出现。比如,在开始时,玩家必须向家长发送“准备就绪”消息,让他们知道自己正在工作。一旦我从孩子那里发送了“就绪”,我如何无限期地“等待”直到下一条消息出现

我不确定我是否正确安装了管道。有人能提供如何使用通信管道的指导,并确认我下面的逻辑吗

为了让父母写信给孩子,我收集了以下信息:

  • 首先创建管道
  • 将父进程分叉到另一个进程(子进程)
  • 将管道的输入连接到父对象的标准输出,并使用dup2和close关闭父对象的读取端
  • 将管道输出连接到孩子的标准输入,然后使用dup2和close关闭孩子的书写部分
  • 使用fdopen()从文件描述符获取文件流,然后打印到该文件流
  • 子进程stdin现在是从父进程打印到stdout的任何内容
  • 这是正确的吗?我试着将这种逻辑应用于孩子和父母之间,但结果却相反

  • 将in管道连接到读取文件流,子程序从其标准输出写入该文件流
  • 将输出管道连接到读取流,父级从中读取

    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");
          }
    
      }
     }
    
  • 我的孩子main有以下内容:

    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;
    }
    
    #包括
    #包括
    #包括
    #包括
    int main(){
    int child2Parent[2];
    int parent2儿童[2];
    字符缓冲区[256];
    文件*p2cStream;
    文件*c2pStream;
    pid_t pid;
    if(管道(家长2孩子)| |管道(家长2孩子)){
    perror(“未能创建管道”);
    退出(退出失败);
    }
    开关(pid=fork()){
    案例-1:/*错误*/
    perror(“未能分叉”);
    打破
    案例0:/*儿童*/
    //将子项设置为从父项读取标准数据
    关闭(parent2Child[1]);/*忽略任何错误*/
    关闭(child2Parent[0]);/*忽略任何错误*/
    if((dup2(parent2Child[0],STDIN_FILENO)<0)
    ||(dup2(child2Parent[1],STDOUT_FILENO)<0){
    perror(“未能复制文件描述符”);
    }否则{
    /*按照惯例,第一个程序参数是程序名*/
    /*此外,execl()仅在失败时返回*/
    execl(“child”、“child”、“2”、“A”、NULL);
    perror(“未能执行子进程”);
    }
    退出(退出失败);
    打破
    默认值:/*父级*/
    关闭(parent2Child[0]);/*忽略任何错误*/
    关闭(child2Parent[1]);/*忽略任何错误*/
    如果(!(p2cStream=fdopen(parent2Child[1],“w”))
    ||!(c2pStream=fdopen(child2Parent[0],“r”)){
    perror(“未能打开流”);
    退出(退出失败);
    }
    if((fprintf(p2cStream,“来自父级的测试消息”)<0)
    ||fclose(p2cStream)){
    perror(“未能给孩子写信”);
    退出(退出失败);
    }
    if(fscanf(c2pStream,“%255[^\n]”,缓冲区)<1){
    perror(“未能阅读孩子的信息”);
    退出(退出失败);
    }
    printf(“子响应:'%s'\n',缓冲区);/*忽略任何错误*/
    打破
    }
    返回退出成功;
    }
    

    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;
    }
    
    #包括
    #包括
    #包括
    #包括
    int main(int argc,char*argv[]){
    字符缓冲区[256]={0};
    如果(扫描(“%255[^\n]”,缓冲区)<0){
    perror(“读取输入失败”);
    退出(退出失败);
    }
    /*
    *如果stdout连接到父级,那么我们可以