使用read()函数时检查EOF

时间:2014-07-24 18:56:37

标签: c named-pipes polling file-descriptor

这是我第一次使用文件描述符进行阅读,现在我已经通过试验和错误测试了大约3个小时,而且我几乎让我的读者工作了!我只需要在命名管道上检查EOF时需要一些帮助。

好的,所以我打开一个(好多个)命名管道,如下所示:

fds[j].fd = open(pipeNameo, O_RDWR) ; // storing it into my file descriptor array

然后我轮询命名管道以查看是否有任何事情发生(轮询在循环内):

int ret = poll(fds, numOfPipesUsed, timeout_msecs);

当某些事情发生时,我通过将写入的文件描述符发送到此函数来处理文件:

int processFileDes( int fd )
{
    char buf[10] ;

    read(fd, buf, 1) ;
    char curr = buf[0] ;
    while (curr != EOF)
    {

        if ( curr == ' ')
        {
            // do nothing it is a space
        }
        else if ( curr == '\n')
        {
            printf("NEW LINE!\n") ;
        }
        else
        {
            int num = curr - '0' ; // turns char number into an int
            printf("Curr Num: %d\n", num) ;
        }

        printf("BEFORE\n"); // Gets stuck here when EOF, this is the string of output
        read(fd, buf, 1) ;
        printf("AFTER\n") ;

        curr = buf[0] ;
    }
printf("Success!\n") ; // this is never printed
return 0 ;
}

一切都运行得很好,除了 read()函数被卡住(等待我想象的回归)一旦所有字符都已被读取。 EOF应该在哪里。我需要能够检查EOF。

我尝试了一种解决方法,通过计算读取的字符数来阻止我的程序读取(因为我知道输入的大小),并且它会起作用,唯一的事情就是当最后一个字符后面有空格时导致我的循环轮询返回1,并在剩余空格(无效输入)上再次运行processFile()以便读取。

请帮忙:')

输入只是一个数字矩阵,如下所示:

0 1 1
2 0 3
1 0 0

3 个答案:

答案 0 :(得分:5)

首先应确保实际上是在管道上命中文件末尾。

当您打开FIFO(命名管道的另一个名称)进行读取时,该过程将一直等到另一个进程打开它进行写入并写入内容。然后它将继续等待更多输入,直到所有进程打开以进行写入已关闭它。

您可以使用mkfifocat在几个终端窗口中对此进行测试:

$ mkfifo test-fifo
$ cat test-fifo     # This is the reading process and will wait for data to read

在另一个终端:

$ cat > test-fifo   # This is the writing process; type here and see it above

现在,如果您关闭写入过程,读取过程将退出,因为它已经到达文件的末尾。

但是,如果您打开两个写入进程,并且只退出一个,则FIFO将保持打开状态,读取结束将不会结束,直到您关闭它们。

因此,一个很容易犯错误的可能性就是让FIFO在某处打开以便写入,因此读取端永远不会得到文件结束条件。需要注意的一件事是,如果这个过程本身也有FIFO打开写入,或者如果产生数据的任何过程只是保持管道打开而不是在它完成后关闭它。

如果您无法确定进程是否已打开管道进行写入,请尝试fuserlsof以识别可能打开它的任何进程。

您的代码的其他一些评论,也可能是问题:

char buf[10] ;

read(fd, buf, 1) ;
char curr = buf[0] ;
while (curr != EOF)

这不是你如何确定你是否使用低级,无缓冲的read原语来命中文件的末尾;这就是你使用像fgetc这样的缓冲stdio操作的方法。使用read,您可以调用所需的长度来读取它,并返回它可以读取的数量(可能小于您要求的长度),如果它位于文件的末尾,则返回0,并且-1错误。如果您没有检查read的返回值,则表示您有错误。请注意,并非所有错误都是致命的。

即使您使用fgetc,此代码也有错误。 fgetc返回一个int,而不是一个char,因此它可以返回整个字符值范围以及EOF的sentinel值。

    printf("BEFORE\n"); // Gets stuck here when EOF, this is the string of output
    read(fd, buf, 1) ;
    printf("AFTER\n") ;

在调用poll之间,通常不应尝试两次读取相同的文件描述符;否则,如果文件描述符上没有更多可用数据,则第二个可以阻止。相反,您应该读取一定数量的数据,但要为read准备好返回的数据少于您请求的数据,然后返回轮询循环以找出现在可用的数据(可能在不同的fd,如果这个没有可用的新数据但另一个没有。)

使用read的方法通常是一次读取整个缓冲区,而不是一次读取一个字符。

答案 1 :(得分:2)

您需要打开非阻塞,因为管道将等待数据可用:

fds[j].fd = open(pipeNameo, O_RDWR | O_NONBLOCK);

答案 2 :(得分:1)

读取的返回值0表示EOF。