7

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

我认为下面的代码会起作用:

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

fseek()不适用于文件描述符。另一种选择是读取管道然后将数据写回,但如果可能的话希望避免这种情况。有什么建议么?

4

13 回答 13

18

根据您的 unix 实现,ioctl/FIONREAD 可能会成功

错误 = ioctl(pipedesc, FIONREAD, &bytesAvailable);

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

于 2008-09-16T13:10:04.990 回答
6

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

于 2008-09-16T12:59:17.713 回答
4

不幸的是,系统并不总是知道管道的大小——例如,如果您将一个长时间运行的进程通过管道传输到另一个命令中,那么源进程可能还没有完成运行。在这种情况下,(即使在理论上)不可能知道还有多少数据会从中产生。

如果您想知道当前可用于从管道中读取的数据量,这将取决于操作系统缓冲和其他难以控制的因素。这里最常见的方法是继续阅读,直到没有任何内容为止(如果你没有得到 EOF,那么源进程还没有完成)。但是,我认为这不是您要寻找的。

所以恐怕没有通用的解决方案。

于 2008-09-16T12:53:09.757 回答
2

几乎不需要知道管道中有多少字节:也许您只想在管道上执行非阻塞 read() ,即。检查是否有任何字节准备好,如果是,则读取它们,但永远不要停止并等待管道准备好。

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

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

于 2008-09-16T16:41:05.310 回答
2

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

于 2008-09-16T12:52:50.570 回答
2

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

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

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

于 2008-09-16T12:52:58.913 回答
0

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

为此,您可以使用类似循环缓冲区的东西

于 2008-09-16T17:22:02.357 回答
0

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

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

于 2009-04-08T18:55:20.693 回答
0

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

你用的是什么平台?

于 2008-09-16T12:53:05.390 回答
0

我不认为这是可能的。管道呈现面向流的协议,而不是面向数据包的协议。IOW,如果您向管道写入两次,一次使用 250 字节,一次使用 520 字节,则无法确定在一个读取请求中您将从另一端获得多少字节。你可以得到 256、256,然后是其余的。

如果您需要将数据包强加到管道上,则需要自己编写预定(或定界)字节数作为数据包长度,然后写入数据包的其余部分。使用select()找出是否有要读取的数据,使用 read() 获得一个合理大小的缓冲区。当您拥有缓冲区时,您有责任确定数据包边界。

于 2008-09-16T13:02:04.603 回答
0

如果你想知道它预计到达的数据量,你总是可以在管道发送的每个 msg 的开头写上 msg 的大小。因此,例如在每个 msg 的开头写入 4 个字节以及数据的长度,然后只读取前 4 个字节。

于 2008-09-16T13:02:17.347 回答
0

正如许多人所回答的那样,您无法便携地告诉要读取多少字节,OTOH您可以做的是轮询管道以获取要读取的数据。首先确保打开管道O_RDWR|O_NONBLOCK- POSIX 要求管道必须打开以进行读取和写入以便能够轮询它。

每当您想知道是否有可用数据时,只需选择/轮询要读取的数据。您还可以通过检查写入来了解管道是否已满,但请参阅下面的注释,具体取决于类型或写入可能不准确。

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

注意:当您选择写入时,即使 poll/select 说您可以写入管道,如果没有足够的空间进行完整写入,写入<= PIPE_BUF也会返回。EAGAIN我不知道如何判断是否有足够的空间来写......这就是我正在寻找的东西(我可能会用\0's 来结束填充PIPE_BUF......在我的情况下,它只是用于测试)。

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

于 2020-09-20T02:05:11.263 回答
-1

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

于 2008-09-16T21:35:29.487 回答