如何使用共享内存段重定向我的命令输出?

时间:2018-01-04 22:50:46

标签: c

我正在尝试使用共享内存重定向命令。

总结一下:我的程序运行如下:我运行./server等待信息,当我运行./client时写入。客户端通过命名管道(mkfifo)将信息发送到服务器。该信息是:要执行的命令类型,数据和共享内存段的名称(使用shm_open ftruncate shm_unlink在客户端创建,最后在char * addr = mmap()....中创建)。如果我在没有重定向标准输出的情况下启动程序,命令的结果将显示在执行服务器的终端中......不过,我希望它出现在客户端中! 这是服务器中的一段代码:

    if ((fd = shm_open(req->shm_name, O_RDWR, S_IRUSR | S_IWUSR)) == -1) {
    perror("shm_open");
    exit(EXIT_FAILURE);
  }

  char *dir = malloc(sizeof(char) * 256);
  int tube[2];
  if (pipe(tube) == -1) {
    perror("tube");
    exit(EXIT_FAILURE);
  }
  switch (fork()) {
  case -1:
    perror("fork");
    exit(EXIT_FAILURE);
  case 0:
    getcwd(dir, 256);
    strcat(dir, "/info_proc");
    char *pid = malloc(10 * sizeof(char));
    sprintf(pid, "%d", req->data);
    if (close(tube[0]) == -1) {
      perror("close");
      exit(EXIT_FAILURE);
    }

      if (dup2(tube[1], STDOUT_FILENO) == -1) {
        perror("dup2");
        exit(EXIT_FAILURE);
      }

      /*if (dup2(fd, STDIN_FILENO) == -1) {
        perror("dup2");
        exit(EXIT_FAILURE);
      }*/

      execl(dir, "info_proc", pid, NULL);
      perror("execl");
      exit(EXIT_FAILURE);
    default:
      wait(NULL);
      /*if (dup2(fd, tube[0]) == -1) {
        perror("dup2");
        exit(EXIT_FAILURE);
      }*/

      if (close(tube[1]) == -1) {
        perror("close");
        exit(EXIT_FAILURE);
      }

      char *received = malloc(sizeof(char) * BUFFER_SIZE);
      while (read(tube[0], &received, sizeof(received)));
      //addr = received;

      /*fd = tube[0];
      if (read(tube[0], &addr, BUFFER_SIZE) == -1) {
        perror("write");
        exit(EXIT_FAILURE);
      }*/

      break;
  }

我该怎么做?

1 个答案:

答案 0 :(得分:0)

虽然您应该能够通过fmemopen()映射到共享内存段,但您需要文件描述符才能通过{{1}执行重定向或其兄弟姐妹。您可以通过dup2()函数为大多数流提取文件描述符,但我发现这对内存流不起作用,可能是因为这些流与内核中的底层打开文件描述不对应。

因此,如果要捕获已执行命令的标准输出(可能是标准错误?),那么您需要将其重定向到管道,并在管道的另一端使用另一个进程服务将数据复制到共享内存段。

这是一种对我有意义的方法:

  • 客户端创建共享内存段,然后
  • 客户端打开fifo并将其请求写入
  • 服务器读取请求并分叉子进程来处理它
  • 孩子打开指定的共享内存段并取消链接
  • 孩子创建一个管道,然后
  • 孩子分叉自己的孩子(孙子)来运行客户的命令
  • 孙子将其标准输出重定向到管道的写入端
  • 子进程从管道读取输出并将其写入共享内存段,直到到达结尾

注意:

  • 虽然您无法使用fileno()直接重定向到共享内存段,但它仍然可以帮助您
  • 您可以使用fmemopen()来获取服务器需要知道的共享内存段的大小
  • 使用fstat()而不是管道,分叉等可以简化孙子的创建和管理。
  • 您需要一种方法告诉客户端输出已准备就绪,并且顺便提一下,要同步对共享内存段的访问。例如,客户端可能会为服务器创建一个命名信号量,以便用于此目的。