2012-11-24 49 views
2

该服务器工作正常,但如果我这样做Perl中,读取使用IO ::选择和IO ::插座:: INET

的bash $(回声-n “ABCD” 堵;睡眠50;回声“ efgh“)| nc localhost 9090

服务器阻塞50秒。在我的完整代码中,我有多个IO::Select::INET。我有另一个套接字监听其他端口(1234),并且当服务器被睡眠阻塞时,我无法在该端口中处理任何内容。我尝试通过getc更改getline,但我只能读取第一个字母“a”并将其阻止。

有人可以帮助我吗?

use common::sense; 
use IO::Select; 
use IO::Socket; 

use constant PORT1 => 9090; 
use constant TIMEOUT => 1; 

my $event_socket = new IO::Socket::INET(Listen => 1, LocalPort => PORT1, ReuseAddr => 1) 
    or die "Can't bind event_socket: [email protected]\n"; 

my $sel = IO::Select->new; 
$sel->add($event_socket); 

my $event_emiter = undef; 

while(1){ 
    foreach my $sock (my @ready = $sel->can_read(TIMEOUT)) { 
     if ($sock == $event_socket) { 
      my $new = $event_socket->accept; 
      binmode($new, ":encoding(UTF-8)"); 
      $sel->add($new); 

      $event_emiter=$new; 

      warn "[event socket] connect from ",$new->peerhost, "\n"; 
     } elsif ($sock == $event_emiter) { 
      unless($sock->eof){ 
       my $recv_data = $sock->getline; 
       warn "[event socket] LOL '$recv_data'\n"; 
      } else { 
       $sel->remove($sock); 
       $sock->close; 
       $event_emiter = undef; 
       warn "[socket] disconnect\n"; 
      } 
     } else { 

      $sel->remove($sock); 
      $sock->close; 

      warn "[socket] disconnect\n"; 
     } 
    } 
} 

回答

5

而不是阅读可用的数据,你正在阅读,直到你阅读一个换行符。始终使用sysread

变化

elsif ($sock == $event_emiter) { 
     unless($sock->eof){ 
      my $recv_data = $sock->getline; 
      warn "[event socket] LOL '$recv_data'\n"; 
     } else { 
      $sel->remove($sock); 
      $sock->close; 
      $event_emiter = undef; 
      warn "[socket] disconnect\n"; 
     } 
    } 

elsif ($sock == $event_emiter) { 
     our $buf; local *buf = \$bufs{$fh}; # alias $buf = $bufs{$fh}; 

     my $rv = sysread($fh, $buf, 64*1024, length($buf)); 
     if (!$rv) { 
      if (defined($rv)) { # EOF 
       # ... Handle anything left in $buf ... 
      } else { # Error 
       # ... Handle error ... 
      } 

      delete $bufs{$fh}; 
      $sel->remove($sock); 
      $sock->close; 
      $event_emiter = undef; 
      warn "[socket] disconnect\n"; 
      next; 
     } 

     while ($buf =~ s/^(.*)\n//) { 
      warn "[event socket] LOL '$1'\n"; 
     } 
    } 

并添加my %bufs;选择外循环。

+0

好的...我试图避免sysread(实际上,避免处理缓冲区)。但是,如果没有其他方法......我的恐惧是在中间选择一些行,并添加一些复杂的方法来将缓冲区添加到此循环的下一步。 –

+0

不确定你的意思。只需用我发布的内容替换'eof'和'getline'。 'warn'[事件套接字]大声笑'$ recv_data'\ n“;''是我的代码中的process_message(”$ 1“)''。 – ikegami

+0

是的,但在“line1 \ r \ nline2 \ r \ nline3 \ r \ n”的情况下,我的缓冲区中可能会捕获“line1 \ r \ nlin”(如果是大行等)。我需要保存最后一个“lin”来连接到下一个缓冲区,但这不是一个大问题,再次感谢 –

0

它会阻止此:

my $recv_data = $sock->getline; 

这是因为函数getline()是阻塞调用,它等待\n。相反,你应该sysread()并组装你的命令在单独的缓冲区。

+0

好吧,但为什么getc块呢? –