我有 Perl 脚本 - 简单的服务器。循环等待connect,写入新的光盘文件。当按下 ctrl + c
时,服务器应该停止。退出前,我想关闭所有文件描述符。这并不容易,因为终端显示错误。
是的,我读了这个线程:
How can I check if a filehandle is open in Perl?
但这对我不起作用。
这是我的主循环:
my $my_socket = new IO::Socket::INET(
LocalHost => $local_host,
LocalPort => $local_port,
Proto => 'tcp',
Listen => 5,
Reuse => 1
);
die "Couldn't create: my_socket $!n " unless $my_socket;
print "Send files.. \n";
while(1) {
my $accepter = $my_socket->accept();
my $count = 0;
#print "$directory.$save_dir/$my_data";
$datetime = localtime();
$datetime =~ s/(?<=\w)\s(?=\w)/_/g;
open my $fh, '>', "$direc/$save_dir/$datetime"
or die "Couldn't open the file";
while(<$accepter>){
chomp;
#last if $count++ ==10;
#print($accepter);
say $fh $_;
}
$SIG{'INT'} = sub {
print "Caught One!\n";
close $fh;
}; #It gives me error. Close fd which is not opened.
}
#print "Received. End \n";
#close $fh;
close $my_socket;
最佳答案
信号处理程序中的代码关闭该文件句柄——并让循环继续。因此,下一次该文件句柄确实已关闭,因此您会收到警告。 (如果问题描述得当,我希望在下一次打印时首先出现问题,但可能有避免这种情况的原因。)
修复,简而言之——在信号处理程序中设置一个标志,仅此而已。在代码中的适当位置检查它,如果已设置,则关闭文件并按 last
退出循环。†(或执行其他一些适当的操作为你的代码。)
关于信号处理程序,我还想多说几句。 %SIG
是一个非常全局化的生物。通过设置 $SIG{INT}
,您已经为解释器中的所有代码更改了它。
为什么不使用 local $SIG{INT}
呢?然后它只在定义它的范围内被改变;见local .我会把这个定义拉到所有可能的循环之外。 (如果你真的想要它全局放置它就在开头,这样它就响亮而清晰而不是隐藏起来。)
有点像
SOME_SCOPE:
{
my $got_signal;
local $SIG{INT} = sub {
#say "Caught: @_";
$got_signal = 1;
};
while (1) {
...
open my $fh, '>', ... or die $!;
while (<$accepter>) {
...
if ($got_signal) {
close $fh;
# $got_signal = 0; # if used again (reset it)
last;
}
say $fh $_;
}
...
}
};
这仍然是一个草图,即使它在更简单的情况下也能正常工作。我必须假设一些事情,首先,您的代码中还有很多事情要做。如果包含且完整的可运行示例可以帮助让我知道,我可以添加它。
† 做不到 last在信号处理程序的子程序中(它不在循环内,即使它是在代码中定义的)。一般来说,至少可以说,在子程序中使用 last
不是一个好主意,因为它会导致代码困惑和不透明。它还具有非常特殊的行为
last
cannot return a value from a block that typically returns a value, such aseval {}
,sub {}
, ordo {}
. It will perform its flow control behavior, which precludes any return value.
(它也带有警告)在这种情况下,您不需要返回一个值,但(即使它有效)您绝对不希望从信号中那样做处理程序。
请注意,即使在问题中有链接,也可以使用 Scalar::Util::openhandle
检查文件句柄是否打开。这在这段代码中会派上用场。
关于linux - 如何在 Perl 中捕获 ctrl+c 并关闭文件描述符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64907212/