C:dup2,管道和fork没有按预期工作

时间:2011-10-28 21:37:10

标签: c fork pipe

我正在尝试做一个简单的分支 - >执行另一个程序 - >对那个孩子的过程说“你好” - >回读一些东西 - >打印收到的内容。

用作孩子的程序只是等待任何输入行,并向stdout打印一些内容,如“你好!”

这是我的“主持人”计划(不起作用):

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

#define IN 0
#define OUT 1
#define CHILD 0

main ()
{
  pid_t pid;
  int pipefd[2];
  FILE* output;
  char buf[256];

  pipe(pipefd);

  pid = fork();    
  if (pid == CHILD)
  {
    printf("child\n");
    dup2(pipefd[IN], IN);
    dup2(pipefd[OUT], OUT);
    execl("./test", "test", (char*) NULL);
  }
  else
  {
    sleep(1);
    printf("parent\n");
    write(pipefd[IN], "hello!", 10); // write message to the process    
    read(pipefd[OUT], buf, sizeof(buf));
    printf("received: %s\n", buf);
  }
}

我明白了:

child
[.. waits 1 second ..]
parent
received: 

我错过了什么?谢谢!

编辑(test.c):

根据要求,这是儿童计划:

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

int getln(char line[])
{
  int nch = 0;
  int c;

  while((c = getchar()) != EOF)
    {
      if(c == '\n') break;
    line[nch] = c;
    nch++;
    }

 if(c == EOF && nch == 0) return EOF;
 return nch;
}

main()
{
  char line[20];

  getln(line);
  printf("hello there!", line);
  fflush(stdout);  
  return 0;
}

6 个答案:

答案 0 :(得分:3)

您总是希望从文件描述符0读取,并使用管道写入文件描述符1 ...您在父进程中将此关系反转。对于您想要做的事情,您可能最终需要两个管道用于父和子之间的双向通信,以避免父进程最终读取它写入管道的内容,因为进程调度是不确定的(即,如果父节点也从同一个管道读取,则不保证子节点读取父节点写入管道的内容,因为父节点可能最终写入然后读取而没有交错子节点进程读取父节点写)。

将您的代码更改为以下内容:

main ()
{
  pid_t pid;
  int pipe_to_child[2];
  int pipe_from_child[2];
  FILE* output;
  char buf[256];

  pipe(pipe_to_child);
  pipe(pipe_from_child);

  pid = fork();    
  if (pid == CHILD)
  {
    printf("child\n");

    //child process not using these ends of the pipe, so close them
    close(pipe_to_child[1]);
    close(pipe_from_child[0]);

    dup2(pipe_to_child[0], fileno(stdin));
    dup2(pipe_from_child[1], fileno(stdout));

    execl("./test", "test", (char*) NULL);
  }
  else
  {
    sleep(1);
    printf("parent\n");
    write(pipe_to_child[1], "hello!\n", 10); // write message to the process    
    read(pipe_from_child[0], buf, sizeof(buf));
    printf("received: %s\n", buf);
  }
}

答案 1 :(得分:2)

你需要两个管道:一个用于子进程的stdin,另一个用于stdout。您不能将管道的两端重新用作两个管道。

此外,父节目的这一行

write(pipefd[IN], "hello!", 10); // write message to the process    

不会写新行,因此孩子中的getln将永远不会返回。 (此外,“你好!”只有六个字符,但你写的是10个。)

答案 2 :(得分:1)

您可能应该使用waitwaitpid

答案 3 :(得分:1)

看起来你的管道描述符已经混淆了。致电pipe()后,pipefd[0]是管道的读取端,pipefd[1]是管道的 write 端。你正在写入读取端,并从写入端读取。

此外,您正在尝试将一个管道用于子进程的stdin和stdout。我不认为这是你想要做的(你需要两个管道)。

答案 4 :(得分:1)

看起来管道的IN / OUT向后 - pipefd[0]是管道的读取端,因此写入它(如父管所做的那样)是荒谬的并且会失败。类似地,pipefd[1]是写端,因此从它读取(如父节点所做)也将失败。您应该始终检查读取和写入调用的返回值,以查看是否出现任何错误

答案 5 :(得分:1)

其他人说管道是单向的,这是我最初想到的。但实际上,这不是我的手册页所说的:

 A read from fildes[0] accesses the data written to fildes[1]
 on  a  first-in-first-out  (FIFO)  basis  and  a  read  from
 fildes[1] accesses the data written to fildes[0] also  on  a
 FIFO basis.

但是,这确实意味着如果父母写入pipefd[0],那么孩子应该从pipefd[1]读取,因此您将管道的错误一侧与孩子的stdin和stdout相关联。

在手册页中,您似乎可以使用一个管道执行此操作。但是使用两个代码可能更清晰。

您似乎将pipefd的每个元素视为一个单独的管道,但事实并非如此。