【问题标题】:Can a pipe in Linux ever lose data?Linux 中的管道会丢失数据吗?
【发布时间】:2011-02-12 12:09:20
【问题描述】:

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

【问题讨论】:

  • 其输不松。松是松动的牙齿
  • @intuited: bad delimiter ")" (缺少左括号)
  • 让我开心,还有 4 个角色去 :)

标签: linux posix pipe


【解决方案1】:

除非机器崩溃,否则它不会丢失数据。但是,很容易误用它并认为您正在丢失数据,因为写入失败并没有写入您请求的所有数据并且您没有检查返回值,或者您在读取时做错了。

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

编辑

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

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

【讨论】:

  • 在加载这个答案后,我实际上放弃了我的答案。您可能想提及 SIGPIPE,en.wikipedia.org/wiki/SIGPIPE
  • 可能有这样一种情况,你杀死了作者或读者,所以作者认为它写了一些读者没有读过的东西?
  • limits.h 中的 PIPE_BUF 会告诉您限制有多大。带有 _PC_PIPE_BUF 的 sysconf() 可以在运行时告诉你(无论如何在 linux 上)
【解决方案2】:

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

  1. 一个进程(写入器)将 n 个字节的数据写入管道,其中 n≤PIPE_BUF。此写入保证是原子的,永远不会阻塞。
  2. 进程(读取器)仅读取 m
  3. 写入器不再尝试写入管道。

因此,内核管道缓冲区将包含 n-m 个字节,当管道的所有句柄都已关闭时,这些字节将丢失。作者不会看到SIGPIPEEPIPE,因为它再也不会尝试写入管道。由于作者永远不会知道管道包含会直接消失的剩余数据,因此可以认为这些数据丢失了。

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

【讨论】:

  • 不应该是FIONREAD吗?注意在 Linux 上,至少 FIONREAD 指示写入描述符(例如 stdout)上有多少数据未读取,但似乎并不表示读者已经离开。如果读者没有读取所有数据就离开了,如果有一种模式让内核向作者发送 SIGPIPE,这对我来说似乎很有用
  • 谢谢,修正了错字。事实上,FIONREAD 并没有表明读者是否已经离开,因此需要定义一个超时。是的,如果发送SIGPIPE,我也会发现它很有用。
【解决方案3】:

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

如果您的意思是由pipe 函数创建的管道,那么答案仍然是否定的。根据this man page,写入一个完整的管道将阻塞,直到读取了足够的数据为写入数据腾出空间。它还指出,管道的大小在 Linux pre-2.6.11 中为 4KB,在 2.6.11 及更高版本中为 64kB。

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-02-08
        • 2017-10-07
        • 2021-08-28
        • 1970-01-01
        • 2023-03-04
        • 1970-01-01
        • 2016-03-31
        相关资源
        最近更新 更多