perl,使用IO :: Select和IO :: Socket :: INET读取阻塞

这台服务器工作正常,但如果我这样做

bash $(echo -n“abcd”; sleep 50; echo“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: $@\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"; } } } 

阅读可用的数据,而不是阅读可用的数据,直到你阅读一个换行符。 总是使用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; 在选择循环之外。

它在这里阻止:

 my $recv_data = $sock->getline; 

这是因为getline()阻止了等待\n呼叫。 相反,你应该sysread()和组装你的命令在单独的缓冲区。