使用CTRL + C终止当前的LWP请求

时间:2017-01-13 05:35:41

标签: perl lwp

我有一个基于Term :: ReadLine和LWP :: UserAgent

的脚本

逻辑是这样的,

while (defined ($_ = $term->readline('console> ')))
{
    next unless $_; chomp;

    if ($_ eq 'exit')
    {
        last;
    }
    &run ($_);
}

sub run {
    my $ua   = LWP::UserAgent->new;
    my $resp = $ua->get (...);

    say $resp->content;
}

run中,它会执行LWP请求。现在,如果按 CTRL + C ,不仅LWP终止,整个perl脚本也会终止。

我只想杀死LWP请求。有任何想法吗?

我可以添加一个SIGINT处理程序,但我不知道处理程序应该做什么

3 个答案:

答案 0 :(得分:2)

将信号转换为异常。

local $SIG{INT} = sub { die "SIGINT\n" };

通常,然后将代码包装在eval BLOCK中,但LWP :: UserAgent会捕获这些异常并返回错误响应。

例如,

use LWP::UserAgent;
my $ua = LWP::UserAgent->new();
my $response = do {
   local $SIG{INT} = sub { die "SIGINT\n" };
   $ua->get("http://localhost/zzz.crx")
};
say $response->is_success ? "Successful" : "Unsuccessful";
say $response->code;
say $response->status_line;

如果没有收到SIGINT,则输出:

Successful
200
200 OK

收到SIGINT时的输出:

Unsuccessful
500
500 SIGINT

答案 1 :(得分:1)

停止代码的一种方法是在子进程中运行它,并在父进程收到SIGINT时父进程信号处理程序中的那个子进程use warnings; use strict; use feature 'say'; $SIG{INT} = \&sigint_handler; # or: $SIG{INT} = sub { ... }; say "Parent $$ start."; my $pid = run_proc(); my $gone_pid = waitpid $pid, 0; # check status, in $? say "Parent exiting"; sub run_proc { my $pid = fork // die "Can't fork: $!"; if ($pid == 0) { # child process say "\tKid, sleep 5 (time for Ctrl-C)"; # run your job here sleep 5; say "\tKid exiting."; exit; } return $pid; } sub sigint_handler { if ($pid and kill 0, $pid) { say "Got $_[0], send 'kill TERM' to child process $pid."; my $no_signalled = kill 15, $pid; } else { die "Got $_[0]" } # or use exit } 。自处理信号以来,父母一直在运行。

kill

大量代码用于诊断打印。一些评论如下

kill $pid, 0仅发送信号。它不以任何方式确保流程终止。使用TERM进行检查,如果进程尚未被收集,则返回true(即使它是僵尸)。在我的系统15上是$pid,即使这很常见,请检查。

信号可能在孩子没有跑步的时候到来。处理程序首先检查SIGINT是否在那里,如果没有,它会死亡/退出,尊重fork。适当改变。

父母if ($pid == 0)退出$pid后立即返回$SIG{TERM}

您可以在孩子中安装SIGINT ,如果需要有序退出,可以清理它。

"Got $_[0] ..."处理程序也将耗尽孩子,因此$SIG{INT} = 'IGNORE';打印两次。如果这是一个问题,请向子项添加处理程序以忽略信号$?。有了这个并且在子项运行时按Ctrl-C命中,输出为

Parent 9334 start.
        Kid, sleep 5 (time for Ctrl-C)
^CGot INT, send 'kill TERM' to child process 9335.
Parent exiting

退出后孩子的状态可以通过system进行检查,请参阅{{1}}和Find out more.

文档:in perlvar(以及forkexec),system%SIG in perlvar,部分waitpidperlipc

如果孩子完成的工作需要与家长沟通,那么还有更多工作要做。但是,添加到问题中的代码段表明情况并非如此。

答案 2 :(得分:0)

您需要在致电$ua->request时提供回电。在该回调中发出die将终止转移。

然后,您需要在Ctrl-C信号处理程序中设置一个标志变量,如果设置了该标志,则需要在回调中设置die

当我回到PC时,当你展示了你的run子程序时,我会写一些代码。

这里有一些看起来正确的代码,但我目前无法测试它

请注意run是任何子例程的可靠标识符,尤其是启动网络传输并打印结果的子例程

sub run {

    my ($url) = @_;

    my $die;
    local $SIG{INT} = sub { $die = 1 };

    my $ua = LWP::UserAgent->new;

    my $resp = $ua->get(
        $url,
        ':content_cb' => sub {
            die "Interrupted LWP transfer" if $die;
            my ($data, $resp, $proto) = @_;
            print $data;
        },
        ':read_size_hint' => 1024
    );

    print "\n";  # Emulate additional newline from `say`
}

请注意,减少:read_size_hint将导致使用较小的数据块更频繁地调用回调。这将改善对 Ctrl-C 的响应,但会降低传输效率