perl, lecture en bloc en utilisant IO :: Select et IO :: Socket :: INET

Ce serveur fonctionne bien mais si je le fais

bash $ (echo -n “abcd”; sleep 50; echo “efgh”) | nc localhost 9090

Le serveur se bloque pendant 50 secondes.Dans mon code complet, j’ai plusieurs IO::Select::INET . J’ai une autre prise d’écoute autre port (1234), et je ne peux rien traiter dans ce port pendant que le serveur est bloqué par le sumil. J’essaie de changer le getline par getc mais je ne lis que la première lettre “a” et ça bloque.

Quelqu’un peut m’aider?

 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"; } } } 

Plutôt que de lire les données disponibles, vous lisez jusqu’à ce que vous lisiez une nouvelle ligne. Toujours utiliser sysread .

Changement

  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"; } } 

Et ajoutez my %bufs; en dehors de la boucle de sélection.

Il bloque ici:

 my $recv_data = $sock->getline; 

C’est parce que getline () bloque l’appel qui attend \n . Au lieu de cela, vous devriez sysread() et assembler votre commande dans un tampon séparé.