关于Perl TCP套接字编程的问题

时间:2010-12-27 01:52:10

标签: perl

以下代码确实运行TCP服务器,该服务器在接收TCP请求时分叉新进程。为什么它会在第一个请求被接受后退出?


#!/usr/bin/perl

use Socket;
use POSIX qw(:sys_wait_h);

sub REAPER {
  1 until -1 == waitpid(-1, WNOHANG);
  $SIG{CHLD} = \&REAPER;
}

$SIG{CHLD} = \&REAPER;
socket(SERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, 1);
$my_addr = sockaddr_in(8080, INADDR_ANY);
bind SERVER, $my_addr;
listen(SERVER, 1000);
REQUEST:
while (accept(CLIENT, SERVER)) {
  if ($pid = fork) {
    close CLIENT;
    next REQUEST;
  }
  die "$!" unless defined $pid;
  close SERVER;
  print CLIENT "hello\n";
  close CLIENT;
  exit;
}

2 个答案:

答案 0 :(得分:3)

它退出是因为accept被信号(SIGCHLD)中断而你没有处理这种情况。在perlipc: Internet TCP Clients and Servers中尝试更复杂的版本(向下滚动到多线程版本)。

另外,请考虑使用一个处理这些细节的模块。 Net::Server::Fork类似于您似乎想要编写的内容。如果您不喜欢那个模块,还有其他模块。

无论如何,这是对您的版本的一些最小修正:

#!/usr/bin/perl

use strict;
use warnings;
use Socket;
use POSIX qw(:sys_wait_h);

sub REAPER {
  local $!;                    # Don't let signal handler mess with $!
  1 until -1 == waitpid(-1, WNOHANG);
  $SIG{CHLD} = \&REAPER;
}

$SIG{CHLD} = \&REAPER;
socket(SERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, 1);
my $my_addr = sockaddr_in(8080, INADDR_ANY);
bind SERVER, $my_addr;
listen(SERVER, 1000);
REQUEST:
while (1) {
  my $paddr = accept(CLIENT, SERVER) || do {
    # try again if accept() returned because a signal was received
    next REQUEST if $!{EINTR};
    die "accept: $!";
  };

  my $pid;
  if ($pid = fork) {
    close CLIENT;
    next REQUEST;
  }
  die "$!" unless defined $pid;
  close SERVER;
  print CLIENT "hello\n";
  close CLIENT;
  exit;
}

答案 1 :(得分:0)

我正在问你 代码如何工作,而不是问为什么不这样做。

if ($pid = fork)分叉,即创建一个处理请求的子进程。在父级中,fork()返回子级的pid,因此父级关闭CLIENT句柄并继续等待下一个请求。只有在子级中,fork()返回0,才会执行if块以外的代码执行,子进程处理请求然后退出,因为父进程将处理等待和处理下一个请求。