AnyEvent::Handleのドキュメントを日本語訳に。
キューの理解とか、イベントループの理解とかまだまだ浅いのが日本語にも出てしまっているかもしれませんが、一助となれば幸いです。誤訳はあると思うので、元のサイトも確認してネ。文書の整形はこれからしていきます。
http://search.cpan.org/~mlehmann/AnyEvent-5.29/lib/AnyEvent/Handle.pm
AnyEvent::Handle 非ブロッキングIOストリームハンドル DESCRIPTION(要約) ストリームのファイルハンドルにおけるイベントベースのIO操作を簡単にする ためのヘルパーモジュールです。 AnyEvent::Introに格好のサンプルが掲載されています。 以降において"byte"といった場合、それは「文字」のことを指しています。 「sysread」と「syswrite」が全てのIOに使用されています。 このモジュールではsysreadとsyswriteにおける文字の扱いが同様に適用されて います。 最小限の設定ではfhもしくはconnect。後はon_errorが必要です。 コールバックは全てハンドルオブジェクトのはじめの引数に設定されます。 METHOD $handle = new AnyEvent::Handle fh => $filehandle, key => value... コンストラクタは key => value 形式の引数をサポートしています。 fh => $filehandle[fh or connect] ファイルハンドルはAnyEvent::Handleオブジェクトが操作します。 ファイルハンドルは、コンストラクタで非ブロッキングモードに設定され、 その状態で使用しつづける必要があります。 (AnyEvent::Util::fh_nonblocking関数を使います) connect => [$host, $service] [fh or connect MANDATORY] AnyEvent::Socket::tcp_connectを利用して指定のホストとポートに接続 してください。$hostはデフォルトのpeernameになります。 また、上記のいずれかか、fhを指定する必要があります。 AnyEvent::Handleが接続している間もストリームの読み取り、キューの 書き込み、プロパティの修正が可能です。 このパラメータが指定されている場合は、on_prepare、on_connect_errorと on_connectコールバックは適切な状況下で呼び出されます on_prepare => $cb->($handle) この(めったに使われない)コールバックは新規接続が試みられる前に 呼び出されます。ただし、ファイルハンドルが作成された後となる。 (接続がすでに確立されているときに変更可能な設定とは対照的に) 実際の接続に必要なパラメータを使用してハンドルを準備するのに使用 することができます。 on_connect => $cb->($handle, $host, $port, $retry->()) このコールバックは、接続が正常に確立されているときに呼び出されます。 hostとportと再試行するコールバックを一緒に引数として渡します。 なんらかの理由でハンドルが機能しなかった場合、次の接続先候補へ$retry コールバックが呼び出されます。その時は読み書きキューやeofステータス、 TLSステータス等のプロパティはリセットされます。 on_connect_error => $cb->($handle, $message) このコールバックは接続が確立できなかった時に呼び出されます。 $!変数には関連するエラーコードが含まれ、$message変数は$!と同様です。 このコールバックが指定されない場合は、on_errorの代わりにfatal error が呼び出されます。 on_error => $cb->($handle, $fatal, $message) エラーコールバックです。名前解決できなかった時や、接続ができなかった時 など何らかのエラーが発生した場合に呼び出されます。 エラーにはfatal errorなものもあります。fatal errorが発生した時は、 error callbackが呼び出された後で->destroyによりハンドルオブジェクトは 消去されます。fatal errorのサンプルはactive read watcherのEOF状態もしくは IO errorsを確認してください。IOでは、片方が自由に接続を閉じることが できれば、EPIPEエラーを報告させないようにすることは容易です。 AnyEvent::Handleは極力、適切なエラーコードを出すようにしていますが、 うまく機能してくれない時もあります。よって可読性のあるmessageを出力 するように設定するのが奨励されています。 非致命的なエラーは再試行されるものもあります。しかし、 このコールバックが発動された場合は、ハンドルオブジェクトを 放棄することをお勧めします。非致命的なエラーの例はタイムアウトエラーや 非フォーマットなデータ等があります。 コールバックへのエントリで$!変数はOSのエラーコードを保持しています。 必須ではないが、このコールバックの設定は強く推奨される。というのも それ以外の場合はエラー通知がなされないからだ。 on_read => $cb->($handle) デフォルトのreadコールバックを設定します。データが到着した時とキューに readリクエストがない場合に呼び出されます。queueコールバックとは違って 少なくとも1byteのデータがread bufferに存在する場合だけに呼び出されます。 read bufferにアクセスするまたはデータを取り除く時は$obj->rbufメソッドか $handle->{rbuf}を直接触ります。read bufferを拡張したり修正したりしては いけません。read bufferの開始からデータを削除することのみできます。 $obj->push_readメソッドでread queueを修正することもできます。 EOFが見つかった時は、AnyEvent::Handleオブジェクトはon_eofコールバックを 呼び出す前にまず、queueに登録されたコールバックとon_readに残っている 全てのデータを供給しようとします。何の進展もない場合は fatal errorがraiseされます。 read queueの中のリクエストと違い、on_read callbackはデータを 必要とするわけではない。EOFと未処理のread requestsがある場合は エラーフラグが設定されます。on_readコールバックでは on_eofコールバックが呼び出される。 on_eof => $cb->($handle) end-of-file状態が見つかった時に呼ばれるコールバックです。 ソケット接続の例でいうと、片方が正常にコネクションを閉じて、 キューのリクエスト読み込みがないような場合です。 (もし読み込み要求があるような場合は予期しない接続closeとして エラーフラグが立ちます) 片方のソケットがデータ送信をやめても、もう片方はデータ書き込みが できます。これはreadソケットが閉じたということで、 eofコールバックを実行後もデータの書き込みができるということです。 EOF状態が検出されてon_eofコールバックが設定されていない場合はfatal errorが発生します。 on_drain => $cb->($handle) 書き込みバッファが空になったときに呼び出されるコールバックを 設定します。すでに空の場合はただちに呼び出されます。 書き込みバッファにデータを追加する場合はpush_writeメソッドを使います。 このコールバックは以下のような場合にです。全ての書き込みデータを 一度にキューイングしたくない場合。複数ファイルの内容をソケットに 書き込むのにファイル全体をメモリに読み込みたくない時や全体のデータを 一度にキューイングしたくない時。そのかわりにキューが空になった ときにだけにファイルからデータを読み込みたい。 timeout => 少数を含む秒を設定 rtimeout => 少数を含む秒を設定 wtimeout => 少数を含む秒を設定 0以外が設定された場合、非アクティブタイムアウトを有効にする。 ファイルハンドルの書き込み・読み込みの成功にかかわらず秒数を 渡すことができる。on_timeoutコールバックが呼び出される。 上記3種のタイムアウトは互いに独立して動作する。 読み書き両方(timeout)、読みだけ(rtimeout)、書き込み(wtimiout)だけ等。 注意:タイムアウト処理は読み書きのリクエストがない時でも アクティブになっています。コネクションをアイドル状態で 維持しようと考えている場合はタイムアウト設定を しないようにすべきです。もしくはon_timeoutコールバックで タイムアウトを無視するようにします。その場合、A nyEvent::Handleは単にtimeoutをリスタートするだけです。 0(デフォルト設定)はタイムアウトを無効にします。 on_timout => $cb->($handle) 非活動でのタイムアウトが経過するたびに呼び出されます。 この関数から返り値を戻した場合、timeoutはリセットされます。 なにかのアクションが起こった時と同様に。 それゆえfatal errorは返さない設定です。 rbuf_max =>定義されている場合に、読み込みバッファが サイズを 超えた時はfatal errorが発生します。 DOS攻撃を回避する等の使い道があります。 信頼できないソースからの接続を受け入れるサーバでは 慎重にデータを受け入れるようにします。 読み込みバッファが次のデータを待ち受ける時、 コールバックが終了するより前に攻撃者が無制限の量の データを遅れないようにすべきです。 autocork => 無効(デフォルト設定)にした場合はpush_writeは 可能な限りすぐにハンドルにデータを書き込もうとします。 書き込みのwatcherを登録するのを回避します。 そして次のイベントループを待ち受けます。しかし、 複数の小さなデータを書き込もうとするような場合は 非効率です。(書き込みにあたってはカーネルの nagleアルゴリズムによって非効率は回避される。 no_delay項目を参照のこと。 このオプションはシステムコールのコストを節約します) 有効にした場合、次のイベントループが到着するまで キューイングされます。小さな書き込みが多数ある場合、 これは効果的です。イベントループごとに一回の書き込みを するような場合は非効率となります(書き込みバッファが よく上限になるような場合も)。また、書き込み遅延を 増すことになります。 no_delay => ソケットに対して小さな書き込みをした場合、 Nagleアルゴリズムによってカーネルは実データを送る前に 一定量のデータを待ち受けることになる可能性があります (つまり遅延が発生するということ)。 Nagleアルゴリズム自体は有益なものです。 遅延をできるだけなくしたい場合はno_delay => 1とします。 デフォルト設定は使用中のOSに依存します。 たいていの場合有効になっている。 このオプションで明示的に設定することができます。 keepalive => デフォルトはdisable設定です。enable設定はソケットに SO_KEEPALIVE設定をします。通常TCP接続が確立されると タイムアウトはありません。それゆえ一旦、接続が確立 されると、片方の接続がなくなった場合でももう片方の 接続は生き続けてしまうことができます。TCP keepaliveは 片方の接続が到達不可になった場合に長期に接続している TCP接続を切断するための安価な方法です。デフォルトは OS依存ですが、TCP keepalivesは2時間で長期接続を切断 します。もしどちらかに応答がない場合は10〜15分程度で切断します。 keepalivesをサポートしていないファイルハンドルに設定 しても無害ですし、長期的に接続するような場合はとても有効です。 oobinline => BSDはTCP緊急データの実装がほとんどめちゃくちゃです。 ほとんどのOSはTCPは仕様に応じて実装していますが、 若干のところで異なるところもあります。 TCP緊急データを操作したい場合はこのフラグを有効 (デフォルトで有効)にすることで、移植性の高い方法を提供しています。 TCP緊急データ上のOOBデータのBSDエミュレーションは セキュリティへの影響があるので、AnyEvent::Handleで 明示的に指定しない限り自動的に有効になります。 接続を確立した後でこのflagを設定するのでは 遅すぎることに注意してください。 read_size => 初期の読み込みブロックサイズです。 に設定した 数字の分だけ、各ループ処理中に読み込みます。 各ハンドルオブジェクトは少なくともこの read buffer分のメモリを消費します。 max_read_sizeも参照してください。デフォルトは2048です。 max_read_size => 動的調整アルゴリズムによって使用される読み込み バッファの最大値。AnyEvent::Handleはそれぞれ read_sizeぶんのbytesを読み込むことができる。 またはread_size * 2がこの設定を上回らないところまで。 デフォルトで131072もしくはread_sizeが上回っている場合はその数値。 low_water_mark => デフォルトで0に設定されています。バッファがこの 設定値に達するか、小さい値であった場合にemptyと 解釈されます。書き込みバッファのemptyの数値設定です。 書き込みバッファから完全に排出される前にデータを書き込むことが できるようになるのでパフォーマンス上とても有益です。 しかしOSのカーネルはたいてい同様にバッファするので ほとんど全ての場合でデフォルト設定で問題ないと思われる。 linger => 0以外に設定された場合(デフォルトは3600)、 AnyEvent::Handleオブジェクトのデストラクタは書き残し データがないかをチェックし、あった場合は残りデータを 書き込むためのウォッチャーをインストールします。 OSがソケット切断時に未処理のデータを処理する方法と 同様の方法でエラーは報告されません。 エンコードできなかった部分的なTLSデータでは動作しません。 その場合データは失われます。stoptlsメソッドが助けに なるかもしれません。 peername => $string リモートサイトを識別するために使用される文字列で、 通常DNSホストネームです。(IDNではない)。 IPアドレスでも。エラーメッセージ用に便利だというのとは 別に、TLS peernameを検証するのにも使われます。 peernameが特定されないもしくはundefの場合は この検証フェーズはスキップされます。 tls => "accept" | "connect" | Net::SSLeay::SSL object このパラメータが設定されているときはTLS(SSL)が有効に なっている時です。AnyEventはコネクションが確立され次第 TLSハンドシェイクををスタートします。 その後データを暗号化します。 TLSプロトコルのエラーはEPROTOシグナルとして発生します。 TLSモードはNet::SSLeayモジュールが必要です。 TLSハンドルは自動的にSSLeayモジュールをロードします。 このモジュール自体はSSLeayモジュールに依存してはいません。 TCPとは異なりTLSはサーバサイドとクライアントサイドが あります。サーバサイドはacceptし、クライアントサイドは connectします。 カスタマイズしたTLS接続オブジェクトを提供することができますが、 AnyEvent::Handleに渡す前にNet::SSLeay::set_connect_state もしくはset_accept_stateを呼び出す必要があります。また、 このモジュールの所有権を取得します。 将来的にAnyEvent::Handleは別のTLS実装に切り替えるかも しれないです。 重要:Net::SSLeayオブジェクトは数字なので間違えやすく クラッシュのもとです。segmentation faultに驚かされる TLSネゴシエーションをスタートする必要がある場合は starttlsメソッドを使ってください。 tls_ctx => $anyevent_tls 新規のTLSコネクションを作成するのにAnyEvent::TLS オブジェクトを使います。もしパラメータが存在しない もしくはundefのときはAnyEvent::Handleは AnyEvent::Handle::TLS_CTXを使います。オブジェクトを 指定する代わりにハッシュリファレンスを設定することも できます。 on_starttls => $cb->($handle, $success[, $error_message]) このコールバックはTLS/SSLハンドシェイクが完了した ときに呼び出されます。もし$successがtrueの場合、 TLSハンドシェイクは成功し、それ以外は失敗となります。 この場合はon_stoptlsは呼び出されません。 $handle->{tls}のセッションはハンドシェイクが 失敗した時でもこのコールバックの中で調べる ことができます。 TLSハンドシェイクの失敗はon_errorコールバックを 呼び出すことはしません。その代わり、 エラーメッセージはon_starttlsに渡されます。 このコールバックがない場合は、ハンドシェイクの 失敗は通常通りにon_errorに渡されます。 注意:このコールバックの中でstarttlsコールバックを 再び呼び出すことはできません。なので、 呼び出す必要がある場合は0秒のタイマーを仕込んでください。 on_stoptls => $cb->($handle) SSLv3/TSLがshutdown/closeし、notify/EOFが通知 された時、このコールバックがセットされていれば、 TLSセッションが開放された後に呼び出されます。 もしこのコールバックがない場合はTLSシャットダウンの 状態は通常のハンドル上のEOFとして扱われます。 $handle->{tls}の中のセッションはこのコールバックの 中で調べることができます。このコールバックはTLS シャットダウンから呼び出されます。EOFシグナルからは 呼び出されません。 json => JSON or JSON::XS object JSONオブジェクトの指定。 指定しない場合はAnyEvent::Handleは適切なものを 必要に応じて作成します。UTF-8エンコードされた JSONテキストを書き込むことになります。 このオプションはJSONモジュールに依存している ので、依存関係は解決しておくこと。 ================================================================ $fh = $handle->fh このメソッドはAnyEvent::Handleオブジェクトを作成 するのに使われるハンドルを返します。 $handle->on_error($cb) on_errorコールバックはこの書式に置き換えることもできます。 $handle->on_eof($cb) on_eofコールバックはこの書式に置き換えることもできます。 $handle->on_timeout($cb) $handle->on_rtimeout($cb) $handle->on_wtimeout($cb) on_timeout, on_rtimeout, on_wtimeoutコールバックはこの 書式に置き換えることができます。$cb = undefが設定された 場合はコールバックを無効にします。(timeoutを除く) $handle->autocork($boolean) 原稿のautocorkの挙動を有効・無効に切り替えます。 この書式の変更は次の書き込みのみに影響します。 $handle->no_delay($boolean) no_delayの設定はこの書式に置き換えることもできます。 $handle->keepalive($boolean) keepaliveの設定はこの書式に置き換えることもできます。 $handle->oobinline($boolean) oobinlineの設定はこの書式に置き換えることもできます。 $handle->on_starttls($cb) on_starttlsコールバックはこの書式に変更することができます。 $handle->on_stoptls($cb) on_stoptlsコールバックはこの書式に変更することができます。 $handle->rbuf_max($max_octets) rbuf_maxの設定はこの書式に置き換えることもできます。 $handle->timeout($seconds) $handle->rtimeout($seconds) $handle->wtimeout($seconds) どれくらいの時間($seconds)でtimeoutするかを設定します。 非アクティブであった時の時間となります。 $handle->timeout_reset $handle->rtimeout_reset $handle->wtimeout_reset タイムアウト値をリセットします。(データの送受信に 関係なく実行されます)呼び出しのコストはお安いです。 ===================== #### WRITE QUEUE #### ===================== AnyEvent::Handleは書き込みと読み込みの2つのキューを処理します。 書き込みキューはシンプルです。キューの最後にデータを追加し、A nyEvent::Handleは自動的にそれを取り除いたりしてくれます。 データが書き込まれて、書き込みのバッファがlow water markまで 達して短い時はon_drainコールバックが呼び出されます。 $handle->on_drain ($cb) on_drainコールバックをセットする、もしくはクリアします。 このメソッドはコールバックを呼び出します。それゆえ コールバックが終了した時はハンドルがdestoryされるかもしれません。 $handle->push_write ($data) キューにはスカラーデータが書き込まれます。メモリの限界 までデータをpushすることができます。AnyEvent::Handelの バッファはカーネルからは独立しています。 このメソッドはコールバックを呼び出す事ができます。 それゆえhandleがdestroyされるかもしれません。 $handle->push_write (type => @args) データを自身でフォーマットするかわりに引数でtypeと typeに応じた引数を与えることでモジュールに渡すこと もできます。パッケージの完全名を渡すことでモジュールの ロードをしてモジュール内部のanyevent_write_type関数を 見つけるということもできます。 定義済みのタイプは以下の通りです。 netstring => $string netstringとして指定された値です。 http://cr.yp.to/proto/netstrings.txtを 参照してください packstring => $format, $data 8進化した文字列(prefixed with an encoded lengthは ちょっとわからん)。Perlのpack関数のように エンコードフォーマットを$formatに指定します。 整数は一つしか指定できません。 json => $array_or_hashref 引数のhashrefもしくはarrayrefをJSONオブジェクトに エンコードします。自身のJSONオブジェクトを提供 しない限りJSONテキストはUTF-8にエンコードされます。 JSONオブジェクト(JSONオブジェクトの配列)は自己終端判別できる ので余計なフレーミングをしないでハンドルの片方からJSONを 書き込んで、他方のハンドルから読み込むことができます。 生成されたJSONテキストは改行(?)が含まれていないことを 保証しています。このモジュールはJSONテキストの後もしくは 間にデリミタを必要としていないからです。 簡易に相互運用できる単純なRPCプロトコルはJSON配列を送り ます。てJSONデータの後は必ず改行が送られます。 (もしくはオブジェクトでもよいのですが、配列は何かと 便利です。) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $handle->push_write(json => ["method", "arg1", "arg2"]); $handle->push_write("\012"); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AnyEvent::Handleレシーバはjsonタイプをしごく単純に扱います。 改行があれればその後には空白が続くという意味合いに 解釈するということです。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $handle->push_read(json => sub {my $array = $_[1]; ...}); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 他の言語は改行で区切られた単一行を読みこんでJSONデコーダ に渡します。 storable => $reference $referenceをStorableモジュールでnfreezeしてハンドル に書き込みます。 $handle->push_shutdown データをソケットに書き込んでから、実際にデータが 書き込まれる前にソケットを閉じたくなる時があります。 一つの方法はon_drainハンドラをコールバックで 書き換える方法です(low water markを0にセットします)。 このメソッドはその方法のショートカットで、 on_drainのコールバックを以下のように置き換えます。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sub { shutdown $_[0]{fh}, 1}#for push_shutdown ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ これは単に書き込み側をシャットダウンし、相手側に EOF状態を通知します。 通常の読み込みキューに依拠することもできます。 on_eofメソッドがその後をハンドリングします。 これが接続をクローズするためのキレイな方法です。 このメソッドはコールバックを呼び出すため、handleを destroyする可能性があります。 custom write types - Package::anyevent_write_type $handle, @args 定義済みの型の代わりにパッケージ名を指定することも できます。anyevent_write_typeを探してロードします。 指定された型が使用されている時はpush_writeは 残りの引数を使用してハンドルオブジェクトとして機能します。 関数は8進数の文字列を返し、書き込みバッファに 書き込まれるように想定されています。なので、 この関数をon-the-wire-format変換器のように考えることができます。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $handle->push_write(My::Type => " ", 1, 2, 3); package My::Type; sub anyevent_write_type { my ($handle, $delim, @args) = @_; join $delim, @args; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ===================== #### READ QUEUE #### ===================== AnyEvent::Handleはハンドルごとに書き込みと読み込みの 2つのキューを管理しています。 読み取りキューは書き込みキューよりも複雑です。on_readを 使った簡単な方法とそれ以外の複雑な方法があります。 簡単なケースでは、on_readコールバックを設定してデータが 到着するたびに呼び出されます。読み取りバッファ ($handle->rbuf)からデータを削除することもできます。 もしくはもっとデータが蓄積されてから取り除くこともできます。 push_readを使えば読み込みキューを変えることもできます。 より複雑なケースでは複数のコールバックをキューしたい時 などがあります。AnyEvent::Handelは新しいデータが到着する たびに最初にキューイングされたコールバックを呼び出します。 コールバックが終了した後は削除されます。 この方法では例えば、3行の読み込み行をpushし、データを 読み込みがそれに続きます。AnyEvent::Handleは順番に それを実行していきます。 例1:EPPプロトコルパーサー。EPPは4バイト長のデータを送ります。 その後、指定されたバイト数のXMLデータが続きます。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $handle->on_read(sub{ shift->unshift_read(chunk => 4, sub { my $len = unpack "N", $_[1]; shift->unshift_read(chunk => $len, sub { my $xml = $_[1]; ... }); }); }); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 例2:あるプロトコルのクライアント実装。最初のリクエストで "OK"か"ERROR"が帰ってくる。ついで64バイトのデータが2番目の リクエストで返ってくる。キューの可用性によって両方の リクエストをパイプすることもできますし、必要によって キューをコールバックの中で操作することもできます。 最初のコールバックが呼ばれ、OKの応答をチェックすると 他のline-readをunshiftします。このline-readは 64バイトデータのコールバックの前にキューイングされます。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $handle->push_write("request 1\015\012"); $handle->push_read(line => sub{ if($_[1] eq "OK"){ $_[0]->unshift_read(line => sub { my $response = $_[1]; .... } } }); $handle->push_write("request 2\015\12"); $handle->push_read(chunk => 64, sub { my $response = $_[1]; }); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $handle->on_read ($cb) 現在設定されているon_readコールバックを置き換えるか クリアします。 このメソッドはコールバックを呼び出すのでhandleが destroyされるかもしれません。 $handle->rbuf read bufferを返します。->{rbuf}を使ってもアクセス することができます。 読み込みバッファに許可されている操作は、バッファの はじめからデータを取り除くという操作だけです。 (データを見ることを除いて。)修正したり追加したりと いうのはバグの原因となります。 注意:読み込みバッファはon_readコールバックの中だけ で使われたり操作されたりするべきです。もしくは push_readかunshift_readが単一のコールバックとして 使われるべき(?)。push_readとunshift_readメソッドは 自身で読み込みバッファを管理します。 $handle->push_read ($cb) $handle->unshift_read ($cb) コールバック関数($cb)をキューの最後に指定する (push_read)。もしくは最初に指定する(unshift_read) コールバックは追加の読み込みデータが到着する度に 呼び出されます。 読み込みバッファに十分なデータがあるかをチェックします。 十分なデータがない場合は空のリストかfalseを 返さなければなりません。その場合は十分なデータが 使用可能になるまで繰り返し呼び出されます (もしくはエラーが検出されるまで)。 十分なデータがある場合はコールバックで指定されて いる通りにデータをキューから取り出し、trueを 返します。trueを返した後、データはキューから 削除されます。 このメソッドはコールバックを呼び出すので、 handleがdestroyされる可能性もあります。 $handle->push_read (type => @args, $cb) $handle->unshift_read (type => @args, $cb) データをパースするコールバックを設定するかわりに 定義済みのパースフォーマットを指定することもできます。 パッケージの完全修飾名を記述し、anyevet_read_type 関数を見つけてくることもできます。 定義済みのタイプは書きの通りです。 chunk => $octets, $cb->($handle, $data) 一度だけこのコールバックを呼び出して$octets bytesを 読み込みます。データを$cbに渡します。 データが少ない場合はコールバックは呼び出されません。 line => [$eol, ]$cb->($handle, $line, $eol) 一度だけこのコールバックを呼び出します。$eolで 設定した行の終端マーカがまでを全て読み込みます。 終端マーカを除いたデータが2番目の引数($line)で コールバックに渡されます。終端マーカは3番目の引数です。 $eolは行の終端マーカで文字列として解釈されます。 さもなければ正規表現オブジェクトとして解釈されます。 $eol変数はオプションで、省略された場合、 qr|\015?\012|として使われます。 ラインマーカが存在しないので、ストリームの最後の 部分的な行は返されることはありません。 regex => $accept[, $reject[, $skip], $cb->($handle, $data) $acceptに正規表現オブジェクトを設定し、マッチする 全てのデータを返します。 例:'\n'で終端する単一行を読み込みます。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $handle->push_read (regex => qr<\n>, sub { ... }); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ もし$rejectが設定されていてundefでない場合、 どういうケースでデータが拒否されるかという意味です。 $acceptに設定されている正規表現にマッチしないで $rejectにマッチした時はEBADMSGエラーを生成します。 これは間違ったデータを素早く拒否するのに便利です。 (タイムアウトやバッファオーバフローを回避します。) 例:空白が続く一つの10進数を期待し、その他のものは 拒否します。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $handle->push_read (regex => qr<^[0-9]+\s>, qr<[^0-9]>, sub {...}); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $skipにundef以外が設定されて、受信したバッファが $acceptにも$rejectにもマッチしないで$skipに マッチした場合に。。マッチしないであろう大きなデータを スキップするのに便利です。ゆえに$acceptや$rejectの 正規表現を最初から使うといったようなことをしないで 大丈夫です。数キロバイト以上が期待されるデータに対して、 実行の価値があります。 例:\015\012\015\012で終了するhttpヘッダを期待して います。ヘッダが大きなことを想定しているので$skipで 最初の部分をスキップしようとしています。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $handle->push_read (regex => qr<\015\012\015\012>, undef, qr<^.*[^\015\012]>, sub {...} ); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ netstring => $cb->($handle, $string) http://cr.yp.to/proto/netstrings.txt を確認してください packstring => $format, $cb->($handle, $string) WRITE QUEUEのpackstringを参照のこと json => $cb->($handle, $hash_or_arrayref) WRITE QUEUEのjsonを参照のこと storable => $cb->($handle, $ref) WRITE QUEUEのstorableを参照のこと custom read types - Package::anyevent_read_type $handle, $cb, @args WRITE QUEUEのcutsom_read_typesを参照のこと $handle->stop_read $handle->start_read まれなケースで、ソケットから何も読み込みたくない時 があります。その時はstop_readを呼び出します。その時は on_readもキューイングされたコールバックも実行されません。 読み込みを再開したい場合はstart_readを呼び出します。 AnyEvent::Handleは自動的にstart_readを実行します。 on_readコールバックを変更した時、または読み込み コールバックをpush/unshiftした時です。自動的に stop_readするのはon_readや読み込みリクエストが キューイングされていない場合です。 このメソッドはTLSモードのときは何の影響も持ちません。 TLSは半二重接続をサポートしていません。 $handle->starttls ($tls[, $tls_ctx]) AnyEvent::Handleオブジェクトが作成されてすぐに TLSネゴシエーションを開始する代わりにこの コールバックを呼ぶことでネゴシエーションの 開始前に処理を記述できます。 TLS通信を開始するのは非同期な操作です。書き込み データをpushし、このstarttlsメソッドを呼び出すと TLSネゴシエーションはすぐに開始されます。その後 キューイングされたデータが送られます。 最初の引数はコンストラクタのtlsメンバーと同じです。 (connect, acceptもしくはNet::SSLeayオブジェクトの いずれかです。) 2番目の引数はオプションのAnyEvent::TLSオブジェクトです。 それは新しいコンテキストを生成するのに使われるハッシュ リファレンスかTLS接続オブジェクトです。 TLSコネクションは$handle->{tls}として存在します。 $handle->{tls_ctx}にあるコンテキストはこのメソッドの 呼び出し後に好みに応じて変更できます。 この関数が完了したとき、ハンドシェイクは既に 開始されていることに注意してください。 OpenSSLのバグにより同じストリームに複数のハンドシェイクが 不可能なこともあります。TLSをストップした後はストリームを 使わないようにするのがベストです。 $handle->stoptls SSL接続をシャットダウンします。適切なEOFを送って 接続先に接続断の通知をします。ただしOpenSSLは 非ブロックシャットダウンをサポートしていないので、 接続断後のストリームの再利用は保証されていません。 $handle->destroy 可能な限りハンドルオブジェクトをシャットダウンします。 コールバックがさらに呼び出されることがないことを保証し、 リソースを可能な限り解放します。destroy後に ハンドルオブジェクト上のコールバックを呼び出したときは 無視されます(空リストが返されます)。 通常、AnyEvent::Handleへのリファレンスを意識することなく シャットダウン可能です。handleの外部からはfatal errorと EOFコールバックは機能します。readとwriteのコールバックは 機能しません。コールバック内部からハンドルオブジェクトを destroyしたい時は明示的にdestroyメソッドを使わなければ なりません。 このメソッドからハンドルオブジェクトをdestroyするのは 利点があります。コールバックも同様に削除されます。 もしコールバックがリファレンスを保持しているだけ (通常はそうです。)なら、それを特にdestroyするなどの 必要はありません。 ハンドルはバックグラウンドでlingerオプションのために まだ存在している可能性があり、残りのデータを 書き出します。 $handle->destroyed ハンドルが->destroyメソッドでdestroyされて いなければ、destroyedメソッドはfalseを返します。 破壊されていればtrueを返します。 ハンドルをdestroyする可能性のあるコールバックが 呼び出された後に、ハンドルがまだ有効であるかを 確認するのに役立ちます。例えば、push_write, starttlsなどや他のメソッドがユーザ定義の コールバックを呼び出します。そして、そのコールバックは ハンドルをdestroyする可能性があります。 コールバックがdestroyメソッドhandleを破壊するので、 時おりこのメソッドでチェックすることで回避することもできます。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $hdl->starttls("accept"); return if $hdl->destroyed; $hdl->push_write(...); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~