如果孩子手动收割,IO::Socket::accept 只能工作一次

Posted

技术标签:

【中文标题】如果孩子手动收割,IO::Socket::accept 只能工作一次【英文标题】:IO::Socket::accept works only once if children reaped manually 【发布时间】:2015-09-15 21:42:06 【问题描述】:

在下面的简单回显服务器中,accept() 在第二次调用时返回undef,如果我使用自己的SIGCHLD 处理程序而不是让 Perl 来处理子进程:

#!/opt/perl5/bin/perl

use IO::Select;
use IO::Socket;
use POSIX qw(WNOHANG);
use strict;
use warnings;

$|=1;

use constant LISTEN_PORT => 9998;

my $server = IO::Socket::INET->new (
                 Proto     => 'tcp',
                 LocalPort => LISTEN_PORT,
                 Listen    => SOMAXCONN,
                 Reuse     => 1);

(! $server) && die "Could not setup server - $!\n";
$server->autoflush(1);


sub reaper 
    while ((my $dead_child = waitpid(-1, WNOHANG)) > 0) 
        print "Reaped PID $dead_child\n";
    
    $SIGCHLD = \&reaper;
;
$SIGCHLD = \&reaper;    ## THIS BLOWS
# $SIGCHLD = 'IGNORE';  ## THIS WORKS

while (my $client = $server->accept()) 
   my $childPid;
   if (! defined($childPid = fork())) 
      die "Could not fork: $!\n";
   
   if ($childPid == 0) 
      print $client $_ while (<$client>);
      $client->shutdown(1);
      exit();
    else 
       print "Spawned PID $childPid\n";
   
   close($client);


print "bye\n";

换句话说:

$ ./echoserver.pl
Spawned PID 20953
Reaped PID 20953
bye

【问题讨论】:

您使用IO::Select 等低级机制手动创建所有这些工作的任何特殊原因......而不是使用它的更高级别包装之一? @LeoNerd,我想要一个在$HOME/lib/perl5 中不使用额外模块的小型便携式脚本;事实上,这就是整个代码。不管怎样,你最喜欢的包装是什么? 如果你想要一些可移植的东西,你可以将所需的模块一起打包成一个文件。这样一来,您仍然可以使用 CPAN 中的任何内容,但要知道它们都会被捆绑到一个文件中。 【参考方案1】:

当您的程序接收到SIGCHLD 信号时,底层$server-&gt;accept() 的系统调用可能会被中断。在这种情况下,accept() 将返回 undef$!$!EINTR 将被设置。

在这种情况下需要更多的防御性编程。这是一种方法:

sub robust_accept 
    my $server = shift;
    for (;;) 
        my $client = $server->accept();
        return $client if $client;
        warn "syserror: $!" if !$!EINTR;
    


while (my $client = robust_accept($server)) 
   ...

【讨论】:

你说得对,我忘记了邪恶,狡猾的EINTR - 非常感谢! IGNORE 处理程序拉到这里有什么有用的恶作剧? IGNORE 将在操作系统级别捕获信号,而 perl 不会意识到它。

以上是关于如果孩子手动收割,IO::Socket::accept 只能工作一次的主要内容,如果未能解决你的问题,请参考以下文章

《父亲写的散文诗》--许飞

我必须手动解构所有对象吗

尽管收获,父母不会等待子进程完成

[hihocoder][Offer收割]编程练习赛58

[Offer收割]编程练习赛33

[Offer收割]编程练习赛11 题目4 : 排队接水