gauche.selector - 簡単なディスパッチャ ¶このモジュールは、sys-select (I/Oの多重化参照)に基づき、
登録されたハンドラにI/Oイベントをディスパッチするためのシンプルな
インタフェースを提供します。
{gauche.selector}
ディスパッチャのインスタンスで、ハンドラを携えてI/Oポートを監視します。
makeメソッドで新しいインスタンスを作れます。
{gauche.selector}
セレクタにハンドラprocを追加します。procは、port-or-fd
(ポートオブジェクトかシステムのファイルディスクリプタを表す整数)が
flagsで指定された条件に合致した場合に呼ばれます。
flagsは、以下のシンボルの1つ以上のリストでなければなりません。
rport-or-fdが読み取り可能になった時点でprocが呼ばれます。
wport-or-fdが書き込み可能になった時点でprocが呼ばれます。
xport-or-fdで例外的な状況が発生した場合にprocが呼ばれます。
procは、2引数で呼ばれます。1つ目はport-or-fdそのもので、
2つ目は条件を表すシンボル、r、wあるいはxです。
同じ条件の下ですでにport-or-fdにハンドラが関連付けられていた場合は、 以前のハンドラがprocで置き換えられます。
{gauche.selector}
port-or-fd、proc、flagsにマッチするハンドラエントリを
削除します。引数のいずれかが#fである場合は、それが何でも良いことを
意味します。例えば、
(selector-delete! selector the-port #f #f)
the-portに関連付けられた全てのハンドラを削除します。
(selector-delete! selector #f #f '(w))
書き込み可能になるのを待っている全てのハンドラを削除します。
{gauche.selector}
ディスパッチャのボディです。selfに登録された条件を待ち、条件が合致すると
それに関連付けられたハンドラを呼びます。
timeout引数が省略されるか偽の場合、このメソッドは永久に待ちます。
タイムアウトの値を与える場合は、マイクロ秒を表す実数か、秒とマイクロ秒を
表す2つの整数のリストを与えます。
戻り値は、ハンドラが呼ばれた回数です。0(ゼロ)は、セレクタがタイムアウト したことを意味します。
ハンドラの中でselfを変更することは安全です。その変更は、次回の
selector-selectの呼び出し以降に反映されます。
echoサーバのシンプルな例を示します。
(use gauche.net)
(use gauche.selector)
(use gauche.uvector)
(define (echo-server port)
(let ((selector (make <selector>))
(server (make-server-socket 'inet port :reuse-addr? #t)))
(define (accept-handler sock flag)
(let* ((client (socket-accept server))
(output (socket-output-port client)))
(selector-add! selector
(socket-input-port client :buffering #f)
(lambda (input flag)
(echo client input output))
'(r))))
(define (echo client input output)
(let ((str (read-uvector <u8vector> 4096 input)))
(if (eof-object? str)
(begin (selector-delete! selector input #f #f)
(socket-close client))
(begin (write-uvector str output)
(flush output)))))
(selector-add! selector
(socket-fd server)
accept-handler
'(r))
(do () (#f) (selector-select selector))))