如何在fread()中禁用缓冲?

7
我正在使用fread()和fwrite()来读写套接字。我相信这些函数是用于缓冲输入和输出的。是否有一种方法可以在仍然使用这些函数的情况下禁用缓冲?
编辑:
我正在构建一个远程桌面应用程序,远程客户端似乎“比服务器慢了一点”,我不知道可能的原因是什么...我认为可能是由于缓冲读写..但使用setvbuf没有起作用。
所谓“滞后”,是指远程桌面客户端落后于服务器几秒钟。服务器在特定时刻所做的事情会在延迟约15-20秒后反映在客户端上。
此外,我不想不使用fread(),因为它是现有代码的一部分。我不想修改它。我最终可以使用write()和read(),但我想避免这样做。

如果你打算给负评,一些评论将不胜感激。 - AnkurVj
4
我也不理解为什么会有人给负评,我点了一个赞。 - Alex Reynolds
我曾经遇到过同样的问题,但没有想到禁用它..!! 所以+1 - Jeegar Patel
请注意,您在向套接字传输数据(或一批数据)之后,也可以直接调用 fflush() 函数将缓冲区内容刷新到套接字。 - nos
@nos 我一定会尝试并查看它是否解决了我的问题。 - AnkurVj
3个回答

8
您可以使用 setvbuf 来针对特定的文件指针禁用缓冲:
setvbuf(fp, NULL, _IONBF, 0);

编辑

将套接字与标准输入混合使用有点棘手,正如Stevens所警告的那样。以下是一些引用。

这三个函数[fseek,fsetpos,rewind]的问题在于它们都调用lseek,在套接字上失败。

处理这个读写问题最简单的方法是:为给定的套接字打开两个标准I / O流:一个用于读取,另一个用于写入。

解决[缓冲问题]的一种方法是通过调用setvbuf来强制输出流成为行缓冲。另一种方法是在每次调用fputs之后调用fflush,强制输出每个回显行。但实际上,这两种解决方案仍然容易出错,并且可能与Nagle算法交互不良


总之:

尽量停止使用stdio使用readwrite代替stdiofreadfwrite是没有意义的。 Stevens提到“行缓冲”输出,因为人们使用stdiofgetsfputs


那么它会影响fread的行为吗?我确实遇到了这个函数,但无法理解它是否适用于fread。 - AnkurVj
1
@AnkurVj 它应该影响所有标准 I/O 操作(即使用 FILE * 的所有操作)。 - cnicutar
我正在构建一个远程桌面应用程序,但是远程客户端似乎比服务器慢了一点,我不知道可能的原因... 我认为这可能是由于缓冲读写造成的,但是使用setvbuf并没有起作用。 - AnkurVj
@DavidS 我已经在问题中添加了一些描述 - AnkurVj
@cnicutar,我不想不使用fread(),因为它是现有代码的一部分。我不想修改它。我最终可以使用write()和read(),但我想避免这样做。也许我会尝试替换它一次,看看是否真的有所不同。 - AnkurVj
显示剩余2条评论

2

使用

int setvbuf ( FILE * stream, char * buffer, int mode, size_t size );

mode
    Specifies a mode for file buffering:
    _IOFBF  Full buffering: On output, data is written once the buffer is full. On Input the buffer is filled when an input operation is requested and the buffer is empty.
    _IOLBF  Line buffering: On output, data is written when a newline character is inserted into the stream or when the buffer is full, whatever happens first. On Input, the buffer is filled up to the next newline character when an input operation is requested and the buffer is empty.
    _IONBF  No buffering: No buffer is used. Each I/O operation is written as soon as possible. In this case, the buffer and size parameters are ignored.

这个函数定义在stdio.h头文件中。


1
“Lagging”指的是远程桌面客户端比服务器慢几秒钟。服务器在某个特定时刻所做的事情会在15-20秒延迟后反映在客户端上。
您需要100%确认两件事情。
1)客户端是否在“fread”中被阻塞?如果没有,那么它之所以滞后是因为它太忙了,无法跟上服务器(或代码已经损坏,并且愚蠢地没有调用“fread”)。在任何一种情况下,缓冲和网络都不是问题的原因。
2)客户端完成对“fread”的调用接收到的总字节数是否比服务器完成对“fwrite”的调用发送的字节数少?如果不是,则“滞后”是因为它误解了一些接收到的数据(未能意识到实际上接收到了一些数据)。在这种情况下,缓冲和网络也不是问题的原因。
我敢打赌,我提到的两件事情中有一件是正确的。
为了澄清第二种情况,如果不清楚,请考虑以下示例:
1)服务器发送一条消息。
2)服务器发送一条消息。

3) 客户端调用fread并获取了两条消息,但由于代码错误,只认为自己收到了一条消息。(也许是因为错误的代码假设消息不能“粘在一起”。)

4) 此时,客户端可能会看起来“滞后”了一条消息,但实际上,客户端的代码只是有问题。客户端已经读取了服务器发送的所有字节。它没有滞后,只是出现了故障。

在排除这两种“繁忙代码”和“错误代码”类型的情况之前,您不应该假设网络出了问题,因为这是最不可能的解释。


  1. 客户端不能错过消息,因为如果错过了,它会立即失败。 (构造是这样的)。所以我100%确定它不会错过消息。
  2. 你所说的阻塞,是指阻塞和非阻塞调用的概念吗?我的fread()在程序读取指定字节数之前是阻塞的。此外,只有一个执行线程。
- AnkurVj
通过“阻塞”,我指的是线程的执行被阻塞,因为它在进行fread调用时正在等待数据。如果它不在等待数据,则滞后可能是由它所做的任何事情引起的,而不是在fread中等待数据。(顺便说一句,我建议不要在套接字上使用fread。它会增加复杂性,没有真正的好处。) - David Schwartz
那么,问题是:当客户端滞后时,它在做什么?它在fread中被阻塞了吗? - David Schwartz
David,我该如何找出它在哪里花费了时间?另外,我应该提到目前服务器和客户端都在同一台物理机上运行...所以网络延迟不应该是一个原因。 - AnkurVj
1
@AnkurVj 你可以记录并加上时间戳,当程序进入 fread 和从 fread 返回时。你可以使用像 callgrind 这样的性能分析工具。 - David Schwartz

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