linux - 如何在 Perl 中捕获 ctrl+c 并关闭文件描述符

标签 linux perl

我有 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 as eval {}, sub {}, or do {}. 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/

相关文章:

linux - bash中的特殊字符替换

linux - 使用 ansible 为多个用户安装 ohmyzsh?

linux - FreeBSD 终端找不到 sdk 命令

linux - 错误 : clGetPlatformIDs -1001 when running OpenCL code (Linux)

Python 相当于 Perl 的 HTTP::Async->next_response

Linux SVN 恢复文件

perl - 为什么我无法在 Ubuntu 18.04 上安装 Perl Net-SNMP

perl - 如何将哈希传递给子例程?

perl - 在简单的 Perl 教程中为模块添加包含路径

perl - 在 Perl 中检查字符串是否为空的正确方法是什么?