sagittarius-websocket

Scheme 処理系 Sagittarius で動く WebSocket クライアントライブラリを公開しました。

https://github.com/SaitoAtsushi/sagittarius-websocket

[追記] 現在では Sagittarius に WebScoket ライブラリが含まれていますので、私の実装を利用する必要はありません。 [/追記]

実際に github に置いたのは半月ほど前なのですが、その時点では Sagittarius の HEAD を必要としたので、 Sagittarius 0.4.9 がリリースされた今のタイミングでブログで紹介することにしました。 つまり、この WebSocket クライアントライブラリを動かすためには 0.4.9 以降の Sagittarius が必要です。

sagittarius-websocket が Sagittarius の最新の機能を使っているというよりは、 sagittarius-websocket を作るにあたって遭遇したバグや不足している機能をツイッタで呟いていると Sagittarius の方がどんどん修正されたという経緯で、まったく有難いことです。

他に公開されている Sagittarius 用ライブラリに倣って CMake を用いるインストールスクリプトを同梱してはいますが、 Windows ではうまく動きません。 sagittarius-config や sagittarius-package といった補助的なコマンドが Windows 版では動かないからです。 実際には rfc/websocket.scm をコピーしているだけなので、妥当なところにコピーして下さい。 Sagittarius をデフォルトの場所にインストールしたなら C:\Program Files\Sagittarius\sitelib\rfc へコピーすればよいです。

sagittarius-websocket にはドキュメントがありませんが、使用例は同梱してあります。 WebSocket についての知識があれば使用例を見れば充分に使い込なせるでしょうが、その使用例を元に簡単な説明をします。

(import (rfc websocket)
        (rnrs))

(define websocket
  (make-websocket-client
   :on-message (lambda(x) (display "response: ") (display x) (newline))
   :on-error raise))

(websocket-connect websocket "wss://echo.websocket.org")
(websocket-send websocket "Hello, world.\n")
(display (websocket-ping websocket 1000))
(websocket-close websocket)
(websocket-wait-close websocket)

まず、 sagittarius-websocket の import spec は (rfc websocket) です。

WebSocket 通信を始めるためにまずすることは websocket オブジェクトの生成です。 make-websocket-client 手続きを使います。 このときキーワード引数によってハンドラを指定します。 指定可能なハンドラは以下のみっつです。

キーワード ハンドラが呼ばれるタイミング ハンドラが受けとる引数
:on-message メッセージを受信したとき ひとつの引数を受取る。 文字列かバイトベクタのいずれか
:on-error エラーが発生したとき ひとつの引数を受取る。 投げられた例外オブジェクト
:on-close コネクションが閉じられたとき 引数を受取らない

エラーハンドリングは厳密ではなく、トラブルからの復旧にはあまり使えないと思います。

次はコネクションの生成です。 先程生成したオブジェクトと接続先を websocket-connect に渡すとコネクションが生成されオブジェクトに結び付けられます。

以降は適宜必要なメッセージを投げて下さい。 websocket-send に websocket オブジェクトと文字列、又はバイトベクタを与えると接続先にメッセージを送ります。 websocket-send はジェネリック関数ですので送るメッセージが文字列かバイトベクタかで陽に使い分けたい場合は websocket-send-string や websocket-send-bytevector を直接に呼出すことも出来ます。 独自のオブジェクトをシリアライズしてから送信するといったようなメソッドを被せるカスタマイズも有用でしょう。

websocket-ping は通信先が稼働中かどうか確かめるための手続きです。 websocket オブジェクトとミリ秒単位のタイムアウト時間を与えると真偽値が返されます。 タイムアウトまでに pong メッセージが返ってくれば真値が返され、そうでなければ偽値です。 タイムアウト時間を省略することも出来て、デフォルトは千ミリ秒です。 一部の WebSocket サーバは一定時間の通信がないと自動的にクローズしてしまうものもあるため、そういった場合の生存確認にも使えます。 ping に対する反応 pong がいつまでに返されなければならないかは規格で明記されておらず、 websocket-ping が偽値を返したとしてもコネクションが切れていたりサーバが無反応だとは限りません。 接続先の性質を考慮してタイムアウト時間を調整するとよいでしょう。

websocket-close は通信先へコネクションを閉じる旨のメッセージを送ります。 クローズのメッセージがサーバ側に了承されたのを確認した後にコネクションは閉じられます。

サーバからメッセージを受信している最中に websocket-close を呼出してクローズメッセージを送った場合には実際にコネクションが閉じられるまでしばらく時間がかかることがあります。 中途半端な状態でスクリプトが終了してしまうと問題が生じる場合には websocket-close の呼出し直後に websocket-wait-close 手続きを呼出して下さい。 websocket-wait-close はコネクションが閉じられるまで待機する手続きです。 サーバから送られるメッセージを一方的に受取る状況で、クローズのメッセージもサーバ側から送られることがわかっている場合には websocket-close の呼出し直後以外で websocket-wait-close を呼出してもかまいません。

Document ID: 20f0340bc976d42242e295b316ce497b