3

インタラクティブなプロセスと通信しようとしています。私は自分の 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

以下は、私がやろうとしていることをシミュレートします:

    #!/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;
    }

上記の例では出力バッファリングが機能しません。どのようなテキストが入力されても、何回エンターが押されても、プログラムはそこにとどまります。それを修正する方法は、発行することです:

    my  $pid = open2( \*READER, \*WRITER, "cat -un" );

「cat -n」だけではなく、「cat -un」に注意してください。-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;
    }

4

1 に答える 1

6

バッファリングには次の3種類があります。

  1. ブロックバッファリング:出力は固定サイズのバッファに配置されます。バッファがいっぱいになると、バッファがフラッシュされます。出力がチャンクで出力されるのがわかります。
  2. ラインバッファリング:出力は固定サイズのバッファに配置されます。バッファは、改行がバッファに追加されたとき、およびバッファがいっぱいになったときにフラッシュされます。
  3. バッファリングなし:出力はOSに直接渡されます。

Perlでは、バッファリングは次のように機能します。

  • ファイルハンドルはデフォルトでバッファリングされます。1つの例外:STDERRはデフォルトでバッファリングされません。
  • ブロックバッファリングが使用されます。1つの例外:STDOUTは、端末に接続されている場合にのみラインバッファリングされます。
  • STDINから読み取ると、STDOUTのバッファがフラッシュされます。
  • 最近まで、Perlは4KBのバッファーを使用していました。現在、デフォルトは8KBですが、Perlのビルド時に変更できます。

この最初の2つは、すべてのアプリケーションで驚くほど標準的です。つまり、次のことを意味します。

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

    ユーザーは人です。非常に遅いデータソースですが、彼は一言でバッファリングしません。わかった

  • interface.pl ----> Process

    interface.plの出力はブロックバッファリングされます。悪い

    以下を追加することで修正されましたinterface.pl

    use IO::Handle qw( );
    WRITER->autoflush(1);
    
  • Process ----> interface.pl

    プロセスの出力はブロックバッファリングされます。悪い

    以下を追加することで修正されましたProcess

    use IO::Handle qw( );
    STDOUT->autoflush(1);
    

    さて、あなたはおそらくあなたがプロセスを変更することはできないと私に言うでしょう。もしそうなら、それはあなたに3つのオプションを残します:

    • ツールが提供するコマンドラインまたは構成オプションを使用して、バッファリングの動作を変更します。私はそのようなオプションを提供するツールを知りません。
    • パイプの代わりに疑似ttyを使用して、ブロックバッファリングの代わりにラインバッファリングを使用するように子をだまします。
    • 終了します。

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

    interface.plの出力はラインバッファリングされます。OK(右?)

于 2012-09-28T16:43:56.770 に答える