我有一个基于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处理程序,但我不知道处理程序应该做什么
答案 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(以及fork,exec),system,%SIG in perlvar,部分waitpid,perlipc
如果孩子完成的工作需要与家长沟通,那么还有更多工作要做。但是,添加到问题中的代码段表明情况并非如此。
答案 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 的响应,但会降低传输效率