8

Windows で以下のコード スニペットを実行しています。クライアントからの読み取り後、サーバーは継続的にリッスンを開始します。一定期間後にこのコマンドを終了したい。

内でalarm()関数呼び出しを使用するmain.plと、Perl プログラム全体 (ここではmain.pl) が終了するため、このシステムコマンドを別の Perl ファイルに配置し、システムalarm.plを使用して元の Perl ファイルでこの Perl ファイル ( )を呼び出して呼び出しました。指図。

しかし、この方法ではsystem()、元の Perl ファイルでも呼び出された Perl ファイルでも、この呼び出しの出力を取得できませんでした。

system()通話を終了する方法、または上記で使用した方法で出力を取得する方法を教えてください。

main.pl

my @output = system("alarm.pl");
print"one iperf completed\n";

open FILE, ">display.txt" or die $!; 
print FILE @output_1; 
close FILE;

アラーム.pl

alarm 30;
my @output_1 = readpipe("adb shell cd /data/app; ./iperf -u -s -p 5001");

open FILE, ">display.txt" or die $!; 
print FILE @output_1; 
close FILE;

どちらの方法display.txtでも常に空です。

4

4 に答える 4

15

ここにはいくつかの個別の問題があります。

まず、アラームによってスクリプトが強制終了されないようにするには、ALRM シグナルを処理する必要があります。アラームのドキュメントを参照してください。これには 2 つのスクリプトは必要ありません。

第二に、システムは出力をキャプチャしません。そのためには、バックティック バリアントのいずれか、またはパイプが必要です。Stackoverflow にはすでにその答えがあります。

第 3 に、alarm.plが display.txtに何かを入れた場合、ファイルを書き込みモードで再度開いたときに main.plそれを破棄します。ファイルを 1 か所に作成するだけで済みます。余分なスクリプトを削除すると、この問題は発生しなくなります。

私は最近 と でいくつかの問題を抱えていましたが、IPC::System::Simple に切り替えるとalarmそれsystemが修正されました。

幸運を、 :)

于 2010-04-01T19:19:17.623 に答える
9

私は一体何を考えていたのですか?このタスクにはバックグラウンド プロセスは必要ありません。関数の例に従って、perldoc -f alarm時間に依存するコードをevalブロックにラップするだけです。

my $command = "adb shell cd /data/app; ./iperf -u -s -p 5001";
my @output;
eval {
    local $SIG{ALRM} = sub { die "Timeout\n" };
    alarm 30;
    @output = `$command`;
    alarm 0;
};
if ($@) {
    warn "$command timed out.\n";
} else {
    print "$command successful. Output was:\n", @output;
}

ブロック内ではeval、通常の方法で出力をキャプチャできます (バッククォート またはqx()またはを使用readpipe)。ただし、呼び出しがタイムアウトした場合、出力はありません。

出力が必要ない場合 (または、プロセス間通信を一緒にハッキングしてもかまわない場合) は、アラームを設定systemし、子プロセスで呼び出しを実行することをお勧めします。

$command = "adb shell cd /data/app; ./iperf -u -s -p 5001";
if (($pid = fork()) == 0) {
    # child process
    $SIG{ALRM} = sub { die "Timeout\n" }; # handling SIGALRM in child is optional
    alarm 30;
    my $c = system($command);
    alarm 0;
    exit $c >> 8;  # if you want to capture the exit status
}
# parent
waitpid $pid, 0;

waitpid子供のsystemコマンドが終了したとき、または子供のアラームが鳴って子供を殺したときに戻ります。$?システムコールの終了コード、または未処理の SIGALRM の場合は何か (私のシステムでは 142)、または SIGALRM ハンドラが を呼び出す場合は 255 を保持しますdie

于 2010-04-01T20:44:40.473 に答える
2

以下を必要とする同様の問題に遭遇しました。

  • システム コマンドを実行し、その出力を取得する
  • x 秒後にシステム コマンドをタイムアウトにする
  • システムコマンドプロセスとすべての子プロセスを強制終了します

Perl IPC と手動の fork & exec についてよく読んだ後、私はこの解決策にたどり着きました。これは、シミュレートされた「バックティック」サブルーチンとして実装されています。

use Error qw(:try);

$SIG{ALRM} = sub {
    my $sig_name = shift;
    die "Timeout by signal [$sig_name]\n";
};

# example
my $command = "vmstat 1 1000000";
my $output = backtick( 
                 command => $command, 
                 timeout => 60, 
                 verbose => 0 
             );

sub backtick {

    my %arg = (
        command => undef,
        timeout => 900,
        verbose => 1,
        @_,
    );

    my @output;

    defined( my $pid = open( KID, "-|" ) )
        or die "Can't fork: $!\n";

    if ($pid) {

        # parent

        # print "parent: child pid [$pid]\n" if $arg{verbose};

        try {
            alarm( $arg{timeout} );
            while (<KID>) {
                chomp;
                push @output, $_;
            }

            alarm(0);
        }
        catch Error with {
            my $err = shift;
            print $err->{-text} . "\n";

            print "Killing child process [$pid] ...\n" if $arg{verbose};
            kill -9, $pid;
            print "Killed\n" if $arg{verbose};

            alarm(0);
        }
        finally {};
    }
    else {

        # child

        # set the child process to be a group leader, so that
        # kill -9 will kill it and all its descendents
        setpgrp( 0, 0 );

        # print "child: pid [$pid]\n" if $arg{verbose};
        exec $arg{command};
        exit;
    }

    wantarray ? @output : join( "\n", @output );
}
于 2010-09-21T19:25:13.660 に答える
-2

システムですでに一般的である場合は、コマンドをラップするために「timeout -n」を使用できます。

于 2010-04-01T23:10:09.100 に答える