Perl双向管道IPC,如何避免输出缓冲

use*_*896 3 perl ipc pipe output-buffering tty

我正在尝试与交互式流程进行沟通.我希望我的perl脚本成为用户和进程之间的"模块化人".该过程将文本放入stdout,提示用户输入命令,将更多文本放入stdout,提示用户输入命令,.......提供原始图形:

 User <----STDOUT---- interface.pl <-----STDOUT--- Process
 User -----STDIN----> interface.pl ------STDIN---> Process
 User <----STDOUT---- interface.pl <-----STDOUT--- Process
 User -----STDIN----> interface.pl ------STDIN---> Process
 User <----STDOUT---- interface.pl <-----STDOUT--- Process
 User -----STDIN----> interface.pl ------STDIN---> Process
Run Code Online (Sandbox Code Playgroud)

以下模拟我正在尝试做的事情:

    #!/usr/bin/perl

    use strict;
    use warnings;

    use FileHandle;
    use IPC::Open2;
    my  $pid = open2( \*READER, \*WRITER, "cat -n" );
    WRITER->autoflush(); # default here, actually
    my $got = "";
    my $input = " ";

    while ($input ne "") {
            chomp($input = <STDIN>);
            print WRITER "$input \n";
            $got = <READER>;
            print $got;
    }
Run Code Online (Sandbox Code Playgroud)

DUe输出缓冲上面的例子不起作用.无论输入什么文本,或者按下了多少输入,程序就会坐在那里.修复它的方法是发出:

    my  $pid = open2( \*READER, \*WRITER, "cat -un" );
Run Code Online (Sandbox Code Playgroud)

注意"cat -un"而不是"cat -n".-u关闭cat上的输出缓冲.当输出缓冲关闭时,这有效.我试图与最可能的缓冲输出进行交互的过程,因为我面临与"cat -n"相同的问题.不幸的是我无法关闭与我通信的进程的输出缓冲,所以我该如何处理这个问题呢?

UPDATE1(使用ptty):

    #!/usr/bin/perl

    use strict;
    use warnings;

    use IO::Pty;
    use IPC::Open2;

    my $reader = new IO::Pty;
    my $writer = new IO::Pty;

    my  $pid = open2( $reader, $writer, "cat -n" );
    my $got = "";
    my $input = " ";

    $writer->autoflush(1);

    while ($input ne "") {
            chomp($input = <STDIN>);
            $writer->print("$input \n");
            $got = $reader->getline;
            print $got;
    }
Run Code Online (Sandbox Code Playgroud)

ike*_*ami 6

缓冲有三种:

  1. 块缓冲:输出放入固定大小的缓冲区.当缓冲区变满时刷新缓冲区.你会看到输出以块的形式出现.
  2. 行缓冲:​​输出放入固定大小的缓冲区.将新行添加到缓冲区并且当它变满时,将刷新缓冲区.
  3. 无缓冲:输出直接传递给操作系统.

在Perl中,缓冲的工作原理如下:

  • 默认情况下,文件句柄是缓冲的.一个例外:默认情况下不缓冲STDERR.
  • 使用块缓冲.一个例外:当且仅当它连接到终端时,STDOUT才是行缓冲的.
  • 从STDIN读取为STDOUT刷新缓冲区.
  • 直到最近,Perl才使用4KB缓冲区.现在,默认值是8KB,但是在构建Perl时可以更改它.

前两个在所有应用程序中都是惊人的标准.这意味着:

  • User -------> interface.pl

    用户是一个人.尽管它是一个非常缓慢的数据源,但他并没有缓冲.

  • interface.pl ----> Process

    interface.pl的输出是块缓冲的.

    通过添加以下内容修复interface.pl:

    use IO::Handle qw( );
    WRITER->autoflush(1);
    
    Run Code Online (Sandbox Code Playgroud)
  • Process ----> interface.pl

    进程的输出是块缓冲的.

    通过添加以下内容修复Process:

    use IO::Handle qw( );
    STDOUT->autoflush(1);
    
    Run Code Online (Sandbox Code Playgroud)

    现在,你可能会告诉我你无法改变进程.如果是这样,那么你有三个选择:

    • 使用工具提供的命令行或配置选项来更改其缓冲行为.我不知道提供这种选择的任何工具.
    • 通过使用伪tty而不是管道来欺骗孩子使用行缓冲而不是块缓冲.
    • 退出.

  • interface.pl -------> User

    interface.pl的输出是行缓冲的.好的(对吧?)