在不调用read()的情况下确定管道的大小

时间:2020-03-05 18:55:49  来源:igfitidea点击:

我需要一个名为SizeOfPipe()的函数,该函数应返回管道的大小我只想知道管道中有多少数据,而不是实际从管道本身读取数据。

我以为下面的代码会工作

fseek (pPipe, 0 , SEEK_END);
*pBytes = ftell (pPipe);
rewind (pPipe);

但是fseekensent在文件描述符上工作。另一种选择是读取管道,然后将数据写回,但如果可能的话,希望避免这种情况吗?

解决方案

回答

通常不可能仅从管道句柄就知道从管道读取的数据量。数据可能通过网络传入,或者由另一个进程动态生成。如果我们需要事先了解,则应安排通过管道将信息发送给我们,或者通过管道另一端的任何处理将信息带外。

回答

没有通用的,可移植的方法来告诉管道中有多少数据而不读取它。至少不在POSIX规范下。

管道是不可搜索的,也不可能将数据放回管道的读取端。

但是,特定于平台的技巧可能是可行的。如果问题是特定于平台的,则编辑问题以使其说出来可能会增加我们获得有效答案的机会。

回答

我认为不可能,不是在两端之间(沿一个方向)提供进程间通信的管道的要点。如果我在该断言中是正确的,则发送可能尚未完成将数据推入管道的操作,因此无法确定长度。

我们正在使用什么平台?

回答

不幸的是,系统无法始终知道管道的大小,例如,如果将长时间运行的进程通过管道传送到另一个命令中,则源进程可能尚未完成运行。在这种情况下,没有任何可能的方法(即使从理论上来说)也要知道要从中输出多少数据。

如果我们想知道当前可能从管道中读取的数据量是可能的,但这将取决于OS缓冲和其他难以控制的因素。这里最常见的方法是继续阅读,直到没有剩下的东西为止(如果我们没有获得EOF,则说明源程序尚未完成)。但是我不认为这是我们想要的。

因此,恐怕没有通用的解决方案。

回答

一些UNIX实现在调用fstat()之后返回可以在st_size字段中读取的字节数,但这是不可移植的。

回答

我认为这是不可能的。管道提供面向流的协议,而不是面向分组的协议。 IOW,如果我们两次写入管道,一次写入250字节,一次写入例如520字节,则无法告诉我们在一个读取请求中从另一端获得多少字节。我们可能会得到256、256,然后剩下的。

如果需要在管道上添加数据包,则需要自己写一些预定(或者定界)的字节作为数据包长度,然后再写入其余数据包。使用select()找出是否有要读取的数据,使用read()获得合理大小的缓冲区。当我们有缓冲区时,确定数据包边界是责任。

回答

如果我们想知道期望到达的数据量,则可以始终在管道发送的每个味精大小为味精的开头写入内容。
因此,例如,在每个msg的开头写入4个字节,并加上数据长度,然后仅读取前4个字节。

回答

根据unix实现,ioctl / FIONREAD可能会解决问题

err = ioctl(pipedesc, FIONREAD, &bytesAvailable);

除非这返回"无效参数"的错误代码(或者任何其他错误),否则bytesAvailable包含当时可用于解除阻止读取操作的数据量。

回答

几乎从来不需要知道管道中有多少字节:也许我们只想在管道上执行无阻塞read(),即。检查是否有任何字节准备就绪,如果有,请读取它们,但不要停止并等待管道准备就绪。

我们可以分两个步骤进行操作。首先,使用select()系统调用来查找数据是否可用。此处是一个示例:http://www.developerweb.net/forum/showthread.php?t=2933

其次,如果select告诉我们数据可用,则以大块大小调用一次read(),并且仅调用一次。它只会读取可用的字节数,或者最大为块的大小(以较小者为准)。如果select()返回true,则read()将始终立即返回。

回答

没有可移植的方法来判断来自管道的数据量。
我们唯一可以做的就是读取和处理数据。

为此,我们可以使用循环缓冲区之类的东西

回答

在Windows上,我们始终可以使用PeekNamedPipe,但是我仍然怀疑那是我们要执行的操作。

回答

我们可以将其包装在具有可回退缓冲的对象中。这仅对于少量数据是可行的。

在C语言中执行此操作的一种方法是定义结构,并为结构包装在管道上运行的所有函数。