在C语言中从文件描述符读取数据

3

(如果我术语有误,请纠正)所以我需要从文件描述符中读取,但是read方法需要一个整数来读取那么多字节的大小,或者我可以使用O_NONBLOCK,但我仍然必须设置一个未知大小的缓冲区大小。这使得它很困难。以下是我的代码:

这是处理所有轮询和mkfifo的方法,并且N已经在主函数中预定义了

struct pollfd pfd[N];
int i;
for(i = 0; i < N; i++)
{
    char fileName[32];
    snprintf (fileName, sizeof(fileName), "%d_%di", pid, i);
    mkfifo(fileName, 0666);
    pfd[i].fd = open(fileName, O_RDONLY | O_NDELAY);
    pfd[i].events = POLLIN;
    pfd[i].revents = 0;

    snprintf (fileName, sizeof(fileName), "%d_%do", pid, i);
    mkfifo(fileName, 0666);
    i++;
    pfd[i].fd = open(fileName, O_WRONLY | O_NDELAY);
    pfd[i].events = POLLOUT;
    pfd[i].revents = 0;
    i--;
}
while(1)
{
    int len, n;
    n = poll(pfd, N, 2000);
    if( n < 0 )
    {   
        printf("ERROR on poll");
        continue;
    }
    if(n == 0)
    {
        printf("waiting....\n");
        continue;
    }
    for(i = 0; i < N; i++)
    {
        char buff[1024]; <---i dont want to do this

        if (pfd[i].revents & POLLIN)
        {
            printf("Processing input....\n");
            read(pfd[i].fd, buff, O_NONBLOCK);
            readBattlefield(buff);
            print_battleField_stats();
            pfd[i].fd = 0;
        }
    }
}

我还看到一篇文章说,一旦read()读取所有的数据,它就会清空管道,这意味着我可以再次使用同一个管道来处理其他传入的数据。但是它并不清空管道,因为我无法再次使用同一个管道。我向我的教授提问,但他只是建议使用类似scanf的函数,但如果scanf需要一个文件流,而poll.fd是一个整数,那么我应该如何使用scanf呢?我的最终问题是,如何通过文件描述符使用scanf或其他方法读取传入的数据?使用scanf将更有助于我处理数据。
编辑:在另一个终端中,我必须输入cat file > (named_file),然后我的主程序将读取输入数据,以下是输入数据的样式:
3 3
1 2 0
0 2 0
3 0 0
前两个数字是网格信息和玩家数量,之后是网格内容,但这只是简化版本,我将处理超过100个玩家和超过1000个网格的情况。

1
将您的缓冲区大小设置为每次处理数据块的大小,然后重复处理该大小的数据块。或者,如果您使用fdopen()函数打开了文件描述符,则可以获取一个FILE *变量,并在其上使用fscanf()函数进行处理。 - Chris Stratton
旁注 - 你的PDF初始化技巧中的 i++i-- 看起来不对。 - keltar
你能发布一个输入数据的示例吗? - ryyker
@keltar 你是对的,我以为它可以工作,但感谢你指出来。 - Steven R
@ChrisStratton,你真是个圣人哈哈,就是这些方法我从来不知道,但它们总是能够拯救我。无论我做多少研究,我都无法偶然发现正确的方法。 - Steven R
1个回答

4

char buff[1024]; <---我不想这样做

那你想怎么做呢?这是它的工作原理。但并不是这样工作的:

read(pfd[i].fd, buff, O_NONBLOCK);

这将编译,因为O_NONBLOCK是一个整数#define,但这是绝对错误的。 read()的第三个参数是要读取的字节数。不是标志。它可能是零,但你所做的是传递一个任意值 - 无论O_NONBLOCK的值如何,它都可能超过1024,即缓冲区的大小。这并不设置阅读非块。recv()类似于read(),并且确实接受第四个参数作为标记,但您无法在文件描述符上使用它。如果要在文件描述符上设置非块,则必须使用open()fcntl()
如何使用扫描或其他方式通过文件描述符读取传入数据?
您可以使用fdopen()从打开的文件描述符创建一个FILE*流。
我还在某个地方读到过一点,即一旦read()读取所有传入数据,它就会清空管道,这意味着我可以再次使用相同的管道来传入其他数据。但是,它不会清空管道,因为我不能再次使用相同的管道。
一旦您到达EOF(因为写入程序关闭了连接),read()将返回0,并立即继续返回0,直到有人重新打开管道。
如果设置描述符非块,则read()将始终立即返回;如果有人连接且没有可读内容,它将返回-1,但errno == EAGAIN 。请参阅man 2 read
definitely是您应该阅读的man fifo;如果有任何您不确定的事情,请根据那个提问一个具体问题。
别忘了:修正那个read()调用。它是错误的。错了。您的教授/ TA /谁也不会错过。

这个问题;我也在某处读到过,一旦read()读取了所有的数据,它就会清空管道,这意味着我可以再次使用同一个管道来接收另一组数据。但事实并非如此。除非发送方关闭管道或接收方故意关闭它,否则管道不会关闭给接收方。 - user3629249
实际上,我刚刚尝试了一下,关于读取文件描述符在EOF后变得无效的说法是错误的;我已经在上面进行了更正。read()会在到达EOF时立即返回0(因为写入者关闭了管道),但是如果另一个写入者使用open()打开管道进行写入,则会停止,您可以继续从新的写入者那里读取。 - CodeClown42

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