在不调用read()的情况下确定管道的大小
我需要一个名为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语言中执行此操作的一种方法是定义结构,并为结构包装在管道上运行的所有函数。