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

Posted

技术标签:

【中文标题】如何在 fread() 中禁用缓冲?【英文标题】:How do I disable buffering in fread()? 【发布时间】:2012-01-31 17:35:33 【问题描述】:

我正在使用 fread() 和 fwrite() 读写套接字。我相信这些功能用于缓冲输入和输出。有什么方法可以让我在使用这些功能的同时禁用缓冲?

编辑:

我正在构建一个远程桌面应用程序,远程客户端似乎“落后于服务器”,我不知道可能是什么原因......我认为这可能是因为缓冲读取和写..但使用 setvbuf 不起作用。

“滞后”是指远程桌面客户端在服务器之后运行几秒钟。服务器在特定时刻所做的事情会在大约 15-20 秒的延迟后反映在客户端上。

另外,我不想不使用-fread(),因为它是现有代码的一部分。我不想修改它。我最终可以使用 write() 和 read(),但我想避免它。

【问题讨论】:

真的,如果您要投反对票,我们将不胜感激 我也不理解反对票。 +1 我过去也遇到过同样的问题,但没想到要禁用它..!!所以+1 请注意,您也可以在编写某些内容(或一批内容)后简单地调用 fflush() 以将缓冲区传输到套接字。 @nos 我一定会尝试一下,看看它是否能解决我的问题。 【参考方案1】:

您可以使用setvbuf 禁用特定文件指针的缓冲:

setvbuf(fp, NULL, _IONBF, 0);

编辑

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

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

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

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


总结:

尝试停止使用stdio使用stdiofreadfwrite 是没有意义的。请直接使用readwrite。 Stevens 谈到“行缓冲”输出,因为人们使用 fgetsfputs 与 stdio

【讨论】:

所以它也会影响 fread 的行为?我确实偶然发现了这个功能,但不明白这是否适用于 fread @AnkurVj 它应该会影响所有 stdio 操作(即所有使用 FILE * 的东西)。 我问的原因是因为我在我的程序中尝试过,它似乎不起作用。客户端可能落后于服务器还有其他原因吗? 我正在构建一个远程桌面应用程序,远程客户端似乎有点落后于服务器,我不知道可能是什么原因......我认为可能是因为缓冲读写..但使用 setvbuf 不起作用 如果您描述了您要解决的实际问题,将会有所帮助。客户端“落后于服务器”是什么意思?客户端是否在fread 中被阻止,并且没有收到服务器传递给已返回的fwrite 调用的字节数?【参考方案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中定义

【讨论】:

【参考方案3】:

“滞后”是指远程桌面客户端在服务器之后运行几秒钟。服务器在特定时刻所做的事情会在大约 15-20 秒的延迟后反映在客户端上。

你需要 100% 确认两件事。

1) 客户端是否在fread 中被阻止?如果没有,那么它就会滞后,因为它太忙而无法跟上服务器的速度(或者代码被破坏并且愚蠢地没有调用fread)。无论哪种情况,缓冲和网络都没有问题。

2) 客户端从其对fread 的已完成调用中收到的总字节数是否少于服务器在其已完成对fwrite 的调用中发送的总字节数?如果不是,那么它就是“滞后”的,因为它误解了它收到的一些数据(没有意识到它得到了一些它实际得到的数据)。在这种情况下,缓冲和网络没有问题。

我会以 10 比 1 的赔率与您打赌,我上面提到的两件事之一就是这种情况。

为了在不清楚的情况下澄清第二种情况,请考虑以下示例:

1) 服务器发送消息。

2) 服务器发送消息。

3) 客户端调用fread 并收到两条消息,但由于代码损坏,只认为它已收到一条消息。 (也许损坏的代码假定消息不能“粘在一起”。)

4) 此时,可能看起来客户端被消息“滞后”了,但实际上,客户端的代码只是被破坏了。客户端读取的字节数与服务器发送的字节数一样多。它没有滞后,只是坏了。

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

【讨论】:

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

以上是关于如何在 fread() 中禁用缓冲?的主要内容,如果未能解决你的问题,请参考以下文章

[Linux]read/write和fread/fwrite有什么区别

如何使用 fread 和 fwrite 函数读写二进制文件?

C语言中fread函数,当文件流缓冲中剩余长度小于需要读取的长度时的问题

如何关闭 write() 系统调用的缓冲?

如何在音轨中找到静音部分

Linux:何时使用分散/收集 IO(readv、writev)与带有 fread 的大缓冲区