使用 read() 函数时检查 EOF

标签 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

最佳答案

您应该首先确保您确实到达了管道上的文件末尾。

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

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

$ 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 的标记值。

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

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

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

关于使用 read() 函数时检查 EOF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24941819/

相关文章:

php - 如何为 8 名玩家创建 7 轮的独特玩家组合

c - 在函数参数数组中放置一个大小有什么意义?

python - 管道没有这样的文件或目录

javascript - Rails javascript 轮询

在 C 中捕获段错误

c# - 什么可能导致本地 WCF 命名管道上的 EndpointNotFoundException?

c# - .NET WCF 命名管道与 COM 对象性能

sockets - POSIX POLLOUT和阻止文件描述符

javascript - 使用 setTimeout 轮询 URL,而不延迟第一次轮询

c - OpenSSL GOST 参数集