linux读取sys调用不会得到EOF

时间:2015-12-05 11:20:54

标签: c linux io pipe eof

首先对不起,如果我的英语不流利和清晰。

我正在努力了解进程之间的管道和通信。我试图实现两个c程序,一个从他从标准输入读取的内容写入某个管道,另一个等待直到管道打开并从中读取并打印到标准输出直到EOF。

以下是编写器管道的代码:

  fd = open(filename, O_RDWR);
  if(fd == -1) print_error();

  while(fgets(buffer, BUFFER_SIZE, stdin) != NULL) {
    if(write(fd, buffer, BUFFER_SIZE) == -1) print_error();
  }

以下是阅读器管道的代码:

while(1) {
    if((fd = open(filename, O_RDWR)) == -1) {
      if(errno == ENOENT) sleep(1);
      else print_error();
    }
    else {
      while(read(fd, buffer, BUFFER_SIZE) != 0) {
        fprintf(stdout, "%s", buffer);
      }
    }
  }

问题是,当我同时运行这两个程序时,基本概念有效,我在写程序中写了一些标准输入,我在另一个终端看到读者程序将它打印到标准输出。问题是,当我通过按CTRL + D为编程器程序发送EOF时,读取器程序仍然等待输入,我知道它不是因为while(1),我在调试器中看到了读取系统调用只是等待输入,并且不明白我们得到了EOF,即使没有输入,行read(fd, buffer, BUFFER_SIZE)也没有评估。

我希望我提供解决问题所需的所有数据,任何人都有任何想法出了什么问题?

2 个答案:

答案 0 :(得分:2)

如果fgets()检测到EOF,则会返回其读取缓冲区中的内容或只返回NULL

在后一种情况下,您希望通过例如关闭管道来通知读取端传输已结束。

  int fd = open(filename, O_RDWR);
  if (fd == -1) 
  {
    perror("open() failed");
  }
  else
  {    
    while (fgets(buffer, BUFFER_SIZE, stdin) != NULL) 
    {
      if (write(fd, buffer, BUFFER_SIZE) == -1) 
      {
        perror("write() failed");
        break;
      }
    }
    if (ferror(stdin))
    {
       perror("fgets() failed");
    }

    close(fd); /* The other end's blocking call to read() would return 0. */
  }

在任何情况下都不会读取EOF之类的内容。 EOF不是一个角色,而是一个国家。

来自man 3 read

  

如果某个进程打开了用于写入的管道[...] read()将阻塞调用线程,直到写入一些数据或管道被具有管道的所有进程关闭             开放写作。

此代码也未涵盖read()失败:

  while(read(fd, buffer, BUFFER_SIZE) != 0) {
    fprintf(stdout, "%s", buffer);
  }

它应该是这样的例子:

  ssize_t result;
  while (0 != (result = read(fd, buffer, BUFFER_SIZE))) 
  {
    if (0 > result)
    {
      if ((EINTR == errno) || (EAGAIN == errno)) 
      {
        continue;
      }

      perror("read() failed");
      break;
    }

    fprintf(stdout, "%s", buffer);
  }

更多这个循环...

while(1) {
  if((fd = open(filename, O_RDWR)) == -1) {
    if(errno == ENOENT) sleep(1);
    else print_error();
  }
  ...
}

...错过close() fd,然后(重新)打开它。

如果读者不写,请通过指定O_RDONLY而不是RDWR来打开管道。

答案 1 :(得分:1)

read也可以在出错时返回-1。如果您的编写器进程未正确关闭其输出流,则可能就是这种情况。因此,您应该明确检查阅读<= 0

但我希望你也知道你周围的while(1)循环会让它立即进入下一轮的read调用,所以你可能也会看到这一点。