2010-02-17 81 views
2

我在Windows(5.10.1的activeperl构建1006)使得在被连接到叉,接受一些JSON数据,并将其写入到数据库中创建用Perl的服务器。在64个客户端连接到服务器后,我遇到了一个问题,当尝试分叉时,错误消息是“资源不可用”。为什么Perl的Windows IO :: Socket在64连接后抱怨“资源不可用”?

这段代码运行在Linux下,我发现许多倒闭的子进程,这是通过增加对父wait()电话解决。但是这并没有解决问题。在Linux下运行代码可以在Windows中执行64个调用。

我也转动起来的情况下,它是在服务器上的限制虚拟的Windows服务器,而是一个新的安装Perl的导致64同样连接限制。

任何想法表示赞赏。


use IO::Socket; 
use Net::hostent; 
use JSON; 
use DBI; 
use Data::Dumper; 

my $port=shift || 9000; 
my $clients_served = 0; 

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

    die "can't setup server" unless $server; 
    print "[Server $0 is running]\n"; 

#### 
# wait for a client to connect 
# once it has, fork to a seperate thread and 
# retrieve the JSON data 
#### 
    while (my $client = $server->accept()) { 
    my $pid = fork(); 

     if ($pid != 0) { 
     print ("Serving client " . $clients_served++ . "\n"); 
     }else{ 
     $client->autoflush(1); 
     my $JSONObject = JSON->new->ascii->pretty->allow_nonref(); 
     my $hostinfo = gethostbyaddr($client->peeraddr); 
     my $client_hostname = ($hostinfo->name || $client->peerhost); 

     printf "connect from %s\n", $client_hostname; 

     print " $client_hostname connected..\n"; 
     syswrite($client, "Reached Server\n", 2048); 
     if (sysread($client, my $buffer, 2048) > 0) { 

      foreach my $tasks($JSONObject->decode($buffer)){ 
      foreach my $task (@$tasks){ 
       insert_record($client_hostname, $task); #empty method, contents does not affect result 
      } 
      } 
     } 

     print " $client_hostname disconnected..\n"; 
     close $client; 
     exit 0; 
     } 
    } 
    $server->close(); 
} 

exit 0; 
+0

64个套接字应该足以应付任何人 - 比尔盖茨 – mob 2010-02-17 21:54:17

+0

哪个Windows版本?非服务器版本对传入连接的数量有各种限制。 – 2010-02-17 22:19:01

+1

我仍然对Windows如何教会人们重新安装是第一件事情之一感到惊讶。 :) – 2010-02-26 01:27:15

回答

2

尝试从已完成的事务中获取僵尸进程。我能得到你的示例代码 继续运行,如果我有一对夫妇更行:

use POSIX ':sys_wait_h'; 

    if ($pid != 0) { 
     print ("Serving client " . $clients_served++ . "\n"); 
     1 while waitpid -1, WNOHANG > 0; 

如果你可能有64个同时连接,你可能想别的东西 - 它没有好安装Windows上的SIGCHLD处理程序。

+0

这很奇怪,如果这是真的 - 没有CHLD处理程序,你不应该*得到*僵尸,除非父母严重崩溃。即使在Windows上。 – hobbs 2010-02-18 09:53:16

+2

在Windows上使用Perl的Unix风格的信号是一个巨大的混乱。具有不同和不相关机制的各种各样的Windows事件被锁定在信号框架中。到目前为止,在Windows中终止子进程(实际上是一个* psuedo进程*,一个单独的线程但不是一个单独的进程)并不会向父进程传递一个SIGCHLD事件,尽管您可以同步使用'waitpid -1'检测是否有孩子已经完成并收获。 – mob 2010-02-18 16:06:17

1

这是一个闪避,因为它不直接回答你的问题,但有时删除错误的最好方法是编写更少的代码 - 为什么不让其他人为你做进程管理和套接字处理 - 即Net::ServerNet::Server::Fork个性提供了与您现在编写的行为相同的行为,但我个人会考虑Net::Server::PreFork

配网::服务器,你的应用程序看起来像:

use strict; 
use warnings; 
use base 'Net::Server::Fork'; 

sub process_request { 
    my $self = shift; 
    # Do JSON stuff here. 
    # The client is attached to *STDIN and *STDOUT. 
} 

# You might omit this and the arguments to run() because 
# Net::Server has command-line and config-file handling too. 

my $port = shift || 90000; 

__PACKAGE__->run(
    proto => "tcp", 
    port => $port, 
); 

这是真的很漂亮整洁,我不得不说。

+0

如果我正在构建Linux的话,我会使用Net :: Server。不幸的是,根据他们的CPAN网站,他们的测试没有通过Windows,这使我看起来在别处。对于Net :: Server解决方案更加优雅,我们不能同意更多。 – JGaudette 2010-02-18 13:57:34

+0

@JGaudette:你在哪里看? CPAN测试人员在Win32上为Net :: Server显示了一组很好的PASSes:http://matrix.cpantesters.org/?dist=Net-Server%200.97;reports=1;os=MSWin32 – hobbs 2010-02-18 18:42:01

1

我挖在Windows(ActiveState的Perl的5.10),Perl的叉的问题。问题在于,在小孩退出之后,仿造为线程的分叉“进程”的句柄没有关闭。似乎有64个线程句柄的限制。因为我没有找到如何关闭这些线程句柄,我已经看了另一种解决方案,发现用真实的线程一起过去64限制(这是来自http://www.perlmonks.org/?node_id=722374):

#! perl -slw 
use strict; 
use IO::Socket; 
use threads; 

our $ADDR ||= 'localhost:35007'; 

my $listener = IO::Socket::INET->new(
    LocalAddr => $ADDR, 
    Listen => 5, 
    Reuse => 1, 
) or die $^E; 

while(my $client = $listener->accept) { 
    async { 
     my($port, $iaddr) = sockaddr_in(getpeername($client)); 
     printf "From %s:%d: %s", join('.',unpack 'C4', $iaddr), $port, $_ 
      while <$client>; 
     close $client; 
    }->detach; 
} 

这还真管用,至少在Windows XP上。任何警告,任何人?

1

我花了很长时间的工作了这一点。

每个Windows perl程序有64个线程的限制,不支持POSIX。

在您分岔一个孩子后,父母需要调用waitpid($ childPID,0)释放该线程,但是这会导致父母阻塞,导致问题:如果父母必须等待孩子完成?

什么不清楚的是,家长可以发出waitpid函数($ childPID,0)在任何时间以后!

当我的孩子线程完成的最后一件事它确实是创建一个文件...

open OUT, ">$$.pid"; 
print OUT $$; 
close OUT; 
exit(0); 

每次家长约到餐桌它会检查.pid文件,并发出waitpid函数为每然后删除.pid文件。

这不会允许同时连接64个以上的连接,但它可以让父母在子线程完成他们的工作时继续,然后在子结束时释放线程。

另一个值得一提的是,孩子应该做的第一件事是关闭监听套接字(问题中的$服务器),以便只有父母将回答新的客户端。

相关问题