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

时间:2008-09-16 12:47:04

标签: c++ c linux unix

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

我认为以下代码可以正常工作

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

但是fseek dosent可以处理文件描述符。另一个选择是读取管道然后写回数据但是如果可能的话,想避免这个,有什么建议吗?

13 个答案:

答案 0 :(得分:17)

根据你的unix实现,ioctl / FIONREAD可能会做到这一点

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

除非返回“invalid argument”(或任何其他错误)的错误代码,否则bytesAvailable包含当时可用于解除阻塞读取操作的数据量。

答案 1 :(得分:5)

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

答案 2 :(得分:4)

不幸的是,系统无法始终知道管道的大小 - 例如,如果要将长时间运行的进程传输到另一个命令,则源进程可能尚未完成运行。在这种情况下,没有可能的方法(甚至在理论上)知道将会有更多的数据出来。

如果您想知道可用于读取管道的当前的数据量,但这将取决于OS缓冲和其他难以控制的因素。这里最常见的方法就是继续阅读,直到没有任何事情要发生(如果你没有获得EOF,那么源程序尚未完成)。但是我认为这不是你想要的。

所以我担心没有通用的解决方案。

答案 3 :(得分:2)

通常不可能仅通过管道手柄知道可从管道读取的数据量。数据可以通过网络进入,也可以由另一个进程动态生成。如果您需要事先了解,您应该安排将信息发送给您 - 通过管道或带外 - 通过管道另一端的任何过程。

答案 4 :(得分:2)

没有通用,可移植的方式来判断管道中有多少数据可用而不读取它。至少不符合POSIX规范。

管道不可寻找,也不可能将数据放回管道的读取端。

但是,平台特定的技巧可能是可能的。如果您的问题是特定于平台的,那么编辑您的问题可能会提高您获得有效答案的机会。

答案 5 :(得分:2)

几乎没有必要知道管道中有多少字节:也许你只想在管道上做一个非阻塞的read(),即。检查是否有任何字节准备就绪,如果是,请读取它们,但永远不要停止并等待以使管道准备就绪。

您可以分两步完成。首先,使用select()系统调用来查明数据是否可用。这里有一个例子:http://www.developerweb.net/forum/showthread.php?t=2933

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

答案 6 :(得分:0)

我认为这不可能,不是管道在两端之间提供进程间通信(在一个方向上)。如果我在该断言中是正确的,那么发送可能还没有完成将数据推入管道 - 因此无法确定长度。

您使用的是什么平台?

答案 7 :(得分:0)

我不认为这是可能的。管道呈现面向流的协议而不是面向分组的协议。 IOW,如果你写一个管道两次,一次用250字节,一次用520字节,就没有办法告诉你在一个读取请求中从另一端得到多少字节。你可以得到256,256,然后是其余的。

如果需要在数据包上强制执行数据包,则需要通过将预定(或分隔)的字节数作为数据包长度写入,然后将剩余的数据包写入数据包来自行完成。使用 select()查看是否有要读取的数据,使用read()来获取合理大小的缓冲区。当你有缓冲区时,你有责任确定数据包边界。

答案 8 :(得分:0)

如果您想知道预期到达的数据量,您可以始终在管道发送的每个消息的开头写入消息的大小。 因此,在每个msg的开头用数据长度写4个字节,然后只读取前4个字节。

答案 9 :(得分:0)

没有可移植的方法来判断来自管道的数据量。 您唯一能做的就是阅读和处理数据。

为此您可以使用类似circular buffer

的内容

答案 10 :(得分:0)

在Windows上,您始终可以使用PeekNamedPipe,但我怀疑这是您想要做的事情。

答案 11 :(得分:0)

您可以使用可以重新缓冲的缓冲将其包装在对象中。这仅适用于少量数据。

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

答案 12 :(得分:0)

正如许多人回答的那样,您无法便携地告诉您要读取多少个字节,OTOH您可以做的是轮询管道以读取要读取的数据。首先,请确保使用O_RDWR|O_NONBLOCK打开管道-POSIX要求开放一个管道以供读取和写入,以便对其进行轮询。

只要您想知道是否有可用数据,只需选择/轮询以读取数据。您还可以通过检查写入来了解管道是否已满。

您将不知道有多少数据,但是请记住,保证PIPE_BUF个字节的写入是原子的,因此,如果您担心管道上有完整的消息,请确保它们适合其中或将它们分开。

但是,当您选择进行写操作时,即使可以写到管道,写操作<= PIPE_BUF也会返回EAGAIN-我不知道如何告诉有足够的写空间,尽管那是什么我一直在寻找(我可能会将\0的内容填充到PIPE_BUF……无论如何都只是为了测试)。

我有一个旧的示例应用程序Perl,它可以以非阻塞模式OCP_Daemon读取一个或多个管道。该代码与使用事件循环在C语言中执行的操作非常接近。