Linux中的管道是否会丢失数据?

时间:2010-04-26 17:05:25

标签: linux posix pipe

它可以包含多少数据的上限?

5 个答案:

答案 0 :(得分:21)

除非机器崩溃,否则它不会丢失数据。很容易误用它,并认为你丢失了数据,或者是因为写入无法写入你请求的所有数据而你没有检查返回值,或者你做了一些错误的读取。

它可以容纳的最大数据量取决于系统 - 如果你尝试写的不多,你可能会得到一个简短的写入,或者编写器将阻塞,直到空间可用。 pipe(7)手册页包含大量有关管道的有用信息,包括(至少在Linux上)缓冲区的大小。 Linux具有4K或64K的缓冲区,具体取决于版本。

修改

蒂姆提到了SIGPIPE,这也是一个看似丢失数据的潜在问题。如果读取器在读取其中的所有内容之前关闭管道,则未读取的数据将被丢弃,并且当写入更多或关闭管道时,编写器将获得SIGPIPE信号,表明已发生这种情况。如果他们阻止或忽略SIGPIPE,他们将收到EPIPE错误。这涵盖了保罗提到的情况。

PIPE_BUF是一个常量,它告诉您 atomic 写入缓冲区的限制。任何大小或更小的写入都将完全成功或阻塞,直到它完全成功(或者如果管道处于非阻塞模式,则给予EWOULDBLOCK / EAGAIN)。它与内核管道缓冲区的实际大小无关,但显然缓冲区的大小必须至少为PIPE_BUF以满足原子性保证。

答案 1 :(得分:3)

发生以下情况时,数据可能会在管道中丢失:

  1. 进程(写入器)将n个字节的数据写入管道,其中n≤PIPE_BUF。这个写保证是原子的,永远不会阻塞。
  2. 进程(读取器)仅读取m
  3. 作者不会再次尝试写入管道。
  4. 因此,内核管道缓冲区将包含n-m个字节,当管道的所有句柄都已关闭时,这些字节将丢失。作者不会看到SIGPIPEEPIPE,因为它永远不会再尝试写入管道。由于作者不会知道管道中包含的遗留数据会消失,因此可以认为这些数据丢失了。

    检测此方法的非标准方法是编写器定义超时并调用FIONREAD ioctl以确定管道缓冲区中剩余的字节数。

答案 2 :(得分:2)

如果你指的是在shell中使用|运算符,那么不会,它不会丢失数据。它只是将左侧标准输出流上的应用程序连接到右侧标准输入流上的应用程序。如果您在应用程序之间管理数据但未获得预期结果,请尝试使用>将第一个应用程序的标准输出重定向到文件,然后使用<将该文件用作标准输入对于第二个应用程序。这样,您可以检查文件并确保以您期望的格式发送数据。

如果你的意思是由pipe函数创建的管道,那么答案仍然是否定的。根据{{​​3}},写入完整管道将阻塞,直到读取足够的数据为写入数据腾出空间。它还指出Linux 2.6-2之前的管道大小为4KB,而2.6.11及更高版本的管道大小为64kB。

答案 3 :(得分:2)

你的管道没有丢失数据。如果您丢失了应用程序中的数据,请尝试使用gdb进行调试。 需要注意的几件事:
1)您的缓冲区是否足够大以容纳您正在阅读的所有数据?
2)检查管道上read()的返回代码是否有错误。
3)您确定要将所有数据写入管道吗?
4)您的写入/读取操作是否被信号中断?即:SIGPIPE?

答案 4 :(得分:1)

您不会丢失数据的原因是,当与管道关联的缓冲区填满时,对write的调用将阻塞,直到读取器清空缓冲区足以完成操作。 (您也可以执行非阻塞写入,但是您有责任确保完成任何可能阻止的写入。)