2

このサーバーは正常に動作しますが、これを行うと

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

サーバーは50秒間ブロックします。私の完全なコードには、複数のがありIO::Select::INETます。別のソケットに他のポート(1234)をリッスンさせていますが、サーバーがスリープによってブロックされている間は、そのポートで何も処理できません。getlinebyを変更しようとしましたgetcが、最初の文字「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";
        }
    }   
}
4

2 に答える 2

6

利用可能なデータを読み取るのではなく、改行を読み取るまで読み取ります。常に使用して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;、選択ループの外側に追加します。

于 2012-11-24T21:34:05.370 に答える
0

ここでブロックします:

my $recv_data = $sock->getline;

これは、getline()が。を待機する呼び出しをブロックしているため\nです。sysread()代わりに、コマンドを別のバッファーにアセンブルする必要があります。

于 2012-11-24T21:34:53.240 に答える