【问题标题】:Is there a way to set up a Linux pipe to non-buffering or line-buffering?有没有办法将 Linux 管道设置为非缓冲或行缓冲?
【发布时间】:2012-01-07 09:49:15
【问题描述】:

我的程序在 Linux 上控制一个外部应用程序,通过管道将输入命令传递给外部应用程序 stdin,并通过管道从外部应用程序 stdout 读取输出结果。

问题是对管道的写入是按块而不是按行缓冲的,因此在我的应用程序接收外部应用程序输出的数据之前会出现延迟。无法更改外部应用程序以添加显式 fflush() 调用。

当我将外部应用程序设置为 /bin/cat -n 时(它回显输入,并添加了行号),它似乎可以正常工作,cat 在每一行之后刷新。强制外部应用程序刷新的唯一方法是向其发送 exit 命令;当它接收到命令时,它会刷新,所有答案都会出现在标准输出上,就在退出之前。

我很确定,Unix 管道是这种进程间通信(伪服务器-客户端)的合适解决方案,但也许我错了。

(我刚刚从一个类似的问题中复制了一些文字:Force another program's standard output to be unbuffered using Python

【问题讨论】:

标签: c linux pipe flush


【解决方案1】:

对于手头的问题,使用 PTY 可能有点过头了(尽管它起作用)。

如果“目标应用程序”(Delphi 命令行实用程序)是动态链接的,可能更简单的解决方案是在应用程序中插入(通过LD_PRELOAD)一个小库。该库只需要实现isatty,并回答true(返回1),无论输出是流向管道还是终端。您可能希望对所有文件描述符执行此操作,或者仅对 STDOUT_FILENO 执行此操作。

大多数 UNIX 实现将调用 isatty 来决定是对给定文件描述符进行完全缓冲还是行缓冲。

嗯,glibc 没有。它调用__fxstat,然后仅在状态指示fd 将转到字符设备时才调用isatty。所以你需要同时插入__fxstatisatty。更多关于库插入here.

【讨论】:

【解决方案2】:

默认情况下,标准输入和标准输出是完全缓冲的,除非它们连接到交互式设备,在这种情况下它们是行缓冲的 [1]。管道是非交互设备。 PTY 交互式设备。 “完全缓冲”的意思是“使用一定大小的一块内存”。

我确定你想要行缓冲。因此,使用主/从 PTY 而不是管道应该会使受控应用程序自动进入正确的缓冲模式。

[1] 详见“stdin(3)”和“setbuf(3)”。

【讨论】:

    【解决方案3】:

    为什么适当地调用fflush(在写入端)对您不起作用?

    您可以使用poll(或其他系统调用,如ppollpselectselect)来检查读取端输入的可用性。

    如果外部应用程序正在使用<stdio.h> 而没有适当地调用fflush(可能是通过setbuf 使其发生在换行符上......),数据将保留在其FILE* 缓冲区内,甚至不会被发送(使用write 系统调用)到管道!

    一个应用程序可以检测它的输出是否是一个终端,例如isatty。但它应该确保发生刷新......

    正如迈克尔狄龙建议的那样,使用pty-s 可能是最好的。但这很难(我忘记了血淋淋的细节)。

    【讨论】:

    • 简单的回答:这不是我的程序。 (很难回答:我们正在尝试将 Delphi 的东西移植到 Linux;外部程序是使用 Wine 运行的 Delphi 命令行实用程序。我不确定 Delphi flush() 的作用,它是否会工作。我们会尝试一下,但即使它有效,问题也值得解决。)
    • 但是如果应用程序没有刷新,那么它是错误到无法使用的地步......
    • 该应用程序在 shell 中运行良好。嗯,我现在有个主意了。
    【解决方案4】:

    不要使用管道。请改用 pty。 Pty(伪 tty)的好处是可以根据需要进行行缓冲,这为您的数据流提供了简单的框架。

    【讨论】:

      猜你喜欢
      • 2014-06-23
      • 1970-01-01
      • 2014-01-30
      • 1970-01-01
      • 2011-07-10
      • 2023-03-08
      • 1970-01-01
      • 2017-09-06
      • 2021-10-13
      相关资源
      最近更新 更多