将子进程的标准输入和标准输出重定向到管道

3

编辑:

解决方案为:
 int c1=dup2(pipes[0][1],STDOUT_FILENO);
 int c2=dup2(pipes[1][0],STDIN_FILENO);


 setvbuf(stdout,NULL,_IONBF,0);

使用SETVBUF设置stdout为非缓冲区。即使我打印了换行符,如果目标不是实际屏幕,我猜它会成为缓冲区。



编辑: 当我在LINE 1之后放置fflush(stdout),并在LINE 4之后放置fflush(fout)时,它按预期工作。但是,如果没有在LINE 1之后放置fflush(stdout),则无法正常工作。问题在于我无法在我计划运行的程序中放置fflush


我正在尝试从我的进程启动另一个程序。我无法访问其代码,但我知道它使用stdin和stdout进行用户交互。我正在尝试通过创建2个管道,fork-ing并将子进程的stdin / stdout重定向到正确的管道端来启动该程序。关键是父进程应该能够通过文件描述符与子进程通信,而其stdin / stdout应保持不变。 POPEN系统调用仅打开单向管道。以下代码几乎有效。

有4行标记为LINE 1..4。

LINE 1是子进程发送到管道, LINE 2是子进程从管道接收, LINE 3是父进程发送到管道, LINE 4是父进程从管道接收,

这只是一个玩具示例,以确保一切正常。问题在于如果取消注释所有4个行LINE1..4,则在终端上看到的输出为

PARENT1: -1
FD: 1 0    4 5    0 1
DEBUG1: 0
DEBUG2: 0

如果只取消注释LINE 1和LINE 3,则只会看到连续的数据流。如果只取消注释LINE 2和LINE 4,则也会发生同样的情况。然而,我想要完全的双向通信。添加已注释的SLEEP也不会改变行为。

问题可能是什么?我想知道为什么没有双向POPN。

int pid;
int pipes[2][2];

pipe(pipes[0]);
pipe(pipes[1]);

pid=fork();

if(pid==0)
  {
  //usleep(1000000);
  close(pipes[0][0]);
  close(pipes[1][1]);

  int c1=dup2(pipes[0][1],STDOUT_FILENO);
  int c2=dup2(pipes[1][0],STDIN_FILENO);
  //int c2=dup2(STDIN_FILENO,pipes[1][0]);

  fprintf(stderr,"FD: %d %d    %d %d    %d %d\n",c1,c2,pipes[0][1],pipes[1][0],STDIN_FILENO,STDOUT_FILENO);

  //FILE*fout=fdopen(pipes[0][1],"w");
  //FILE*fin =fdopen(pipes[1][0],"r");
  while(1)
    {
    static int c1=0;
    fprintf(stderr,"DEBUG1: %d\n",c1);
    printf("%d\n",c1);                      // LINE 1
    fprintf(stderr,"DEBUG2: %d\n",c1);
    scanf("%d",&c1);                        // LINE 2
    fprintf(stderr,"DEBUG3: %d\n",c1);
    c1++;
    }
  //fclose(fout);
  //fclose(fin);
  return 0;
  }

close(pipes[0][1]);
close(pipes[1][0]);

char buffer[100];
FILE*fin=fdopen(pipes[0][0],"r");
FILE*fout=fdopen(pipes[1][1],"w");
while(1)
  {
  int c1=-1;
  printf("PARENT1: %d\n",c1);
  fscanf(fin,"%d",&c1);                         // LINE 3
  printf("Recv: %d\n",c1);

  fprintf(fout,"%d\n",c1+1);                    // LINE 4
  printf("PARENT3: %d\n",c1+1);
  }
fclose(fin);
fclose(fout);

回答自己的问题是可以的!你应该将解决方案发布为答案,然后接受它,而不是编辑原始问题。 - Jonathon Reinhart
1个回答

1

您的代码很长,我不确定是否已经完全理解,但为什么不使用 select ?您是想将子进程的输出重定向到第三个进程中,还是想在父进程中使用它?

下面的例子是使用子进程中的 cat 命令。

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

int     main()
{
  pid_t pid;
  int   p[2];


  pipe(p);
  pid = fork();
  if (pid == 0)
    {
      dup2(p[1], 1); // redirect the output (STDOUT to the pipe)
      close(p[0]);
      execlp("cat", "cat", NULL);
      exit(EXIT_FAILURE);
    }
  else
    {
      close(p[1]);
      fd_set rfds;
      char      buffer[10] = {0};

       while (1)
        {
          FD_ZERO(&rfds);
          FD_SET(p[0], &rfds); 
          select(p[0] + 1, &rfds, NULL, NULL, NULL); //wait for changes on p[0]
          if(FD_ISSET(p[0], &rfds))
            {
              int       ret = 0;
              while ((ret = read(p[0], buffer, 10)) > 0) //read on the pipe
                {
                  write(1, buffer, ret); //display the result
                  memset(buffer, 0, 10);
                }
            }
        }
    }
}

实际上我找到了解决方案。使用SETVBUF将stdout设置为非缓冲区(即使我打印换行符,如果目标不是真正的屏幕,它也会变成缓冲)。 - Swetko
我这样做的原因是我要对我启动的程序中的PRINT-EVAL循环进行编程响应。 - Swetko
@user1068779 很高兴你找到了解决方案。 你仍然可以在父进程中向p[1]写入响应。 - Alexis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接