我需要一个调用的函数SizeOfPipe()
,它应该返回管道的大小——我只想知道管道中有多少数据,而不是实际从管道本身读取数据。
我认为下面的代码会起作用:
fseek (pPipe, 0 , SEEK_END);
*pBytes = ftell (pPipe);
rewind (pPipe);
但fseek()
不适用于文件描述符。另一种选择是读取管道然后将数据写回,但如果可能的话希望避免这种情况。有什么建议么?
根据您的 unix 实现,ioctl/FIONREAD 可能会成功
错误 = ioctl(pipedesc, FIONREAD, &bytesAvailable);
除非这返回“无效参数”(或任何其他错误)的错误代码,否则 bytesAvailable 包含当时可用于解除阻塞读取操作的数据量。
st_size
一些 UNIX 实现在调用 之后返回可以在字段中读取的字节数fstat()
,但这不是可移植的。
不幸的是,系统并不总是知道管道的大小——例如,如果您将一个长时间运行的进程通过管道传输到另一个命令中,那么源进程可能还没有完成运行。在这种情况下,(即使在理论上)不可能知道还有多少数据会从中产生。
如果您想知道当前可用于从管道中读取的数据量,这将取决于操作系统缓冲和其他难以控制的因素。这里最常见的方法是继续阅读,直到没有任何内容为止(如果你没有得到 EOF,那么源进程还没有完成)。但是,我认为这不是您要寻找的。
所以恐怕没有通用的解决方案。
几乎不需要知道管道中有多少字节:也许您只想在管道上执行非阻塞 read() ,即。检查是否有任何字节准备好,如果是,则读取它们,但永远不要停止并等待管道准备好。
您可以分两步完成。首先,使用 select() 系统调用来确定数据是否可用。一个例子在这里:http ://www.developerweb.net/forum/showthread.php?t=2933
其次,如果 select 告诉您数据可用,则调用 read() 一次,并且只调用一次,并且块大小很大。它只会读取可用的字节数,或者读取块的大小,以较小者为准。如果 select() 返回 true,read() 将始终立即返回。
通常,仅从管道句柄就无法知道可以从管道中读取的数据量。数据可能通过网络传入,或者由另一个进程动态生成。如果您需要预先知道,您应该安排将信息发送给您 - 通过管道或带外 - 通过管道另一端的任何进程。
没有通用的、可移植的方法来判断管道中有多少数据可用,而无需读取它。至少不在 POSIX 规范下。
管道不可搜索,也不可能将数据放回管道的读取端。
不过,特定于平台的技巧可能是可能的。如果您的问题是特定于平台的,那么编辑您的问题并这样说可能会提高您获得有效答案的机会。
没有可移植的方法来判断来自管道的数据量。您唯一能做的就是读取和处理数据。
为此,您可以使用类似循环缓冲区的东西
您可以将其包装在带有可以倒带的缓冲的对象中。这仅适用于少量数据。
在 C 中执行此操作的一种方法是定义 stuct 并包装所有在管道上为您的结构运行的函数。
我认为这是不可能的,不是管道的目的是提供两端之间的进程间通信(在一个方向上)。如果我在那个断言中是正确的,那么发送可能还没有完成将数据推送到管道中——所以不可能确定长度。
你用的是什么平台?
我不认为这是可能的。管道呈现面向流的协议,而不是面向数据包的协议。IOW,如果您向管道写入两次,一次使用 250 字节,一次使用 520 字节,则无法确定在一个读取请求中您将从另一端获得多少字节。你可以得到 256、256,然后是其余的。
如果您需要将数据包强加到管道上,则需要自己编写预定(或定界)字节数作为数据包长度,然后写入数据包的其余部分。使用select()找出是否有要读取的数据,使用 read() 获得一个合理大小的缓冲区。当您拥有缓冲区时,您有责任确定数据包边界。
如果你想知道它预计到达的数据量,你总是可以在管道发送的每个 msg 的开头写上 msg 的大小。因此,例如在每个 msg 的开头写入 4 个字节以及数据的长度,然后只读取前 4 个字节。
正如许多人所回答的那样,您无法便携地告诉要读取多少字节,OTOH您可以做的是轮询管道以获取要读取的数据。首先确保打开管道O_RDWR|O_NONBLOCK
- POSIX 要求管道必须打开以进行读取和写入以便能够轮询它。
每当您想知道是否有可用数据时,只需选择/轮询要读取的数据。您还可以通过检查写入来了解管道是否已满,但请参阅下面的注释,具体取决于类型或写入可能不准确。
您不会知道有多少数据,但请记住,写入PIPE_BUF
字节数保证是原子的,因此如果您担心管道上有完整的消息,只需确保它们适合其中或将它们拆分.
注意:当您选择写入时,即使 poll/select 说您可以写入管道,如果没有足够的空间进行完整写入,写入<= PIPE_BUF
也会返回。EAGAIN
我不知道如何判断是否有足够的空间来写......这就是我正在寻找的东西(我可能会用\0
's 来结束填充PIPE_BUF
......在我的情况下,它只是用于测试)。
我有一个旧的示例应用程序 Perl,它可以在非阻塞模式下读取一个或多个管道OCP_Daemon。该代码非常接近您在 C 中使用事件循环执行的操作。
在 Windows 上,您始终可以使用PeekNamedPipe
,但我怀疑这就是您想要做的。