以下代码确实运行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;
}
答案 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块以外的代码执行,子进程处理请求然后退出,因为父进程将处理等待和处理下一个请求。