5

ローカルホストでリッスンし、基本的な呼び出しと応答の種類のインターフェイスを提供するローカル サービスの作成に取り組んでいます。私が始めたいのは、telnet 経由で接続でき、受信した内容をエコーできるベビー サーバーです。

AnyEvent はこれに最適だと聞いたことがありますが、AnyEvent::Socket のドキュメントには、これを行う方法の良い例が示されていません。これを AnyEvent、AnyEvent::Socket、AnyEvent::Handle で構築したいと思います。

現在、小さなサーバー コードは次のようになっています。

#!/usr/bin/env perl

use AnyEvent;
use AnyEvent::Handle;
use AnyEvent::Socket;

my $cv = AnyEvent->condvar;

my $host = '127.0.0.1';
my $port = 44244;

tcp_server($host, $port, sub {
    my($fh) = @_;

    my $cv = AnyEvent->condvar;

    my $handle;
    $handle = AnyEvent::Handle->new(
        fh => $fh,
        poll => "r",
        on_read => sub {
             my($self) = @_;
             print "Received: " . $self->rbuf . "\n";
             $cv->send;
        }
    );

    $cv->recv;
});

print "Listening on $host\n";

$cv->wait;

これは機能せず、localhost:44244 に telnet で接続すると、次のようになります。

EV: error in callback (ignoring): AnyEvent::CondVar: 
recursive blocking wait attempted at server.pl line 29.

telnet 経由で接続できる小さなシングル スレッド サーバーを作成し、与えられたものを出力してさらに入力を待つ方法を理解すれば、そこからさらに多くのことができると思います。何か案は?

4

3 に答える 3

6

コールバック内でブロックしています。それは許可されていません。これを処理するにはいくつかの方法があります。私の好みは、tcp_server コールバック内からCoroスレッドを起動することです。しかし、Coro がなければ、このようなものがあなたが探しているものかもしれません:

#!/usr/bin/env perl5.16.2

use AnyEvent;
use AnyEvent::Handle;
use AnyEvent::Socket;

my $cv = AE::cv;

my $host = '127.0.0.1';
my $port = 44244;

my %connections;
tcp_server(
           $host, $port, sub {
               my ($fh) = @_;

               print "Connected...\n";

               my $handle;
               $handle = AnyEvent::Handle->new(
                                               fh => $fh,
                                               poll => 'r',
                                               on_read => sub {
                                                   my ($self) = @_;
                                                   print "Received: " . $self->rbuf . "\n";
                                               },
                                               on_eof => sub {
                                                   my ($hdl) = @_;
                                                   $hdl->destroy();
                                               },
                                              );
               $connections{$handle} = $handle; # keep it alive.

               return;
           });

print "Listening on $host\n";

$cv->recv;

condvar を 1 つだけ待っていることに注意してください。そして、AnyEvent::Handle オブジェクトをより長く存続させるために、ハンドルを保存しています。$self->rbuf をクリーンアップする作業は、読者の演習問題として残されています :-)

質問のクロスポスト、回答も:-)

于 2012-11-07T00:34:23.197 に答える
1

AnyEvent についても良いことを聞いたことがありますが、使用したことはありません。過去に、IO::Select を使用して小さなノンブロッキング サーバーを作成しました。そのモジュールのドキュメントに例があります(数行追加しました):

use IO::Select;
use IO::Socket;

$lsn = new IO::Socket::INET(Listen => 1, LocalPort => 8080);
$sel = new IO::Select( $lsn );

while(@ready = $sel->can_read) {
    foreach $fh (@ready) {
        if($fh == $lsn) {
            # Create a new socket
            $new = $lsn->accept;
            $sel->add($new);
        }
        else {
            # Process socket
            my $input = <$fh>;
            print $fh "Hello there. You said: $input\n";

            # Maybe we have finished with the socket
            $sel->remove($fh);
            $fh->close;
        }
    }
}
于 2012-11-07T00:19:22.790 に答える
0

あなたの condvar がそこで何をトリガーしようとしているのかわかりません。次のような状態を送信するために使用します。

#!/usr/bin/env perl

use AnyEvent;
use AnyEvent::Handle;
use AnyEvent::Socket;

my $host = '127.0.0.1';
my $port = 44244;

my $exit = AnyEvent->condvar;

tcp_server($host, $port, sub {
    my($fh) = @_;

    my $handle; $handle = AnyEvent::Handle->new(
        fh => $fh,
        poll => "r",
        on_read => sub {
             my($self) = @_;
             print "Received: " . $self->rbuf . "\n";
             if ($self->rbuf eq 'exit') {
               $exit->send;
             }
        }
    );

});

print "Listening on $host\n";

$exit->recv;
于 2012-11-06T23:14:31.363 に答える