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

Perl双向管道IPC,如何避免输出缓冲,perl,ipc,pipe,output-buffering,tty,Perl,Ipc,Pipe,Output Buffering,Tty,我试图通过一个互动的过程进行沟通。我希望我的perl脚本成为用户和进程之间的“模仿者”。该过程将文本放入标准输出,提示用户输入命令,将更多文本放入标准输出,提示用户输入命令。。。。。。。提供了基本图形: User <----STDOUT---- interface.pl <-----STDOUT--- Process User -----STDIN----> interface.pl ------STDIN---> Process User <----STDO

我试图通过一个互动的过程进行沟通。我希望我的perl脚本成为用户和进程之间的“模仿者”。该过程将文本放入标准输出,提示用户输入命令,将更多文本放入标准输出,提示用户输入命令。。。。。。。提供了基本图形:

 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
注意“cat-un”而不仅仅是“cat-n”-u关闭cat上的输出缓冲。当输出缓冲被关闭时,此功能将正常工作。我尝试与最有可能的缓冲区输出交互的过程,因为我面临与“cat-n”相同的问题。不幸的是,我无法在与之通信的进程上关闭输出缓冲,因此如何处理此问题

更新1(使用ptty):

#/usr/bin/perl
严格使用;
使用警告;
使用IO::Pty;
使用IPC::Open2;
my$reader=新IO::Pty;
my$writer=新IO::Pty;
my$pid=open2($reader,$writer,“cat-n”);
我的$got=“”;
我的$input=“”;
$writer->autoflush(1);
而($input ne“”){
chomp($input=);
$writer->print($input\n”);
$got=$reader->getline;
打印$got;
}

~

有三种缓冲:

  • 块缓冲:将输出放入固定大小的缓冲区。缓冲区满时会刷新。您将看到输出以块的形式出现
  • 行缓冲:将输出放入固定大小的缓冲区。当向缓冲区添加换行符并使其变满时,缓冲区将被刷新
  • 无缓冲:输出直接传递到操作系统
  • 在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);
      
    • Process-->interface.pl

      进程的输出是块缓冲的

      通过将以下内容添加到
      过程中来修复:

      use IO::Handle qw( );
      STDOUT->autoflush(1);
      
      现在,你们可能会告诉我你们不能改变这个过程。如果是这样的话,您将有三个选择:

      • 使用工具提供的命令行或配置选项更改其缓冲行为。我不知道有什么工具能提供这样的选择
      • 通过使用替代管道,愚弄孩子使用行缓冲而不是块缓冲
      • 退出

    • interface.pl------>用户

      interface.pl
      的输出是行缓冲的正常(对吗?)


    感谢您的详细解释。我一直在谷歌上搜索,看到很多关于使用ptty的解释。ptty上的示例甚至cPan文档都非常模糊。我还没有采纳你的建议(尚未),但在阅读本文之前,我“转换”了我的代码以使用ptty,但它仍然不起作用。你能告诉我我是否做得对吗?或者用上面的代码给我举个例子。我将研究IO::Pty::Easy。只是想知道块缓冲的问题是什么?为什么进程只是坐在那里而不是发送块?我不在乎它是一行一行地回来还是作为一个街区回来。您是否暗示管道本质上是块缓冲的?如果是这样的话,为什么“awk{print$2}”| df-h | grep“是什么“工作?为什么这些不会因为缓冲而挂起?唯一的问题是你说你不想要它他们不是坐在那里不发送,而是坐在那里等待输入不,是程序在缓冲
    df
    不会挂起等待输入,因为
    df
    不接受任何输入。与您所说的相反,
    grep
    确实挂起等待输入(因为
    df
    的输出肯定是块缓冲的,但是
    df
    完成得非常快,所以
    grep
    只挂起一眨眼。那么为什么原始程序不工作呢?如果进程坐在那里等待输入和interface.pl通过stdout发送,那么进程不应该把它当作STDIN,做它的事情,然后输出吗(作为块、线或其他)退出STDOUT,让interface.pl在其stdin上接收数据?进程坐在那里等待输入,因为interface.pl目前没有发送任何数据。从stdin中没有任何数据可获取。如果有,它就会接收。interface.pl最终将4K或8K放入管道中,进程将在发生时立即开始读取数据。
     open2总是打开它自己的管道,你不能给它Pty。有关使用
    IO::Pty::Easy
    的简单示例,请参阅。
        #!/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;
        }
    
    use IO::Handle qw( );
    WRITER->autoflush(1);
    
    use IO::Handle qw( );
    STDOUT->autoflush(1);