§WebSocket
§Comet ソケットの代わりに WebSocket を使う
Comet ソケットは Web ブラウザへイベントをリアルタイムに送信するためのいわばハックです。また、Comet はサーバからクライアントへの一方向の通信しかサポートしません。サーバへイベントを PUSH 送信する場合は、AJAX リクエストを使います。
Note: クライアントからサーバへリアルタイムに通信を行う別の方法として、入力データのチャンクを受信するカスタムの
BodyParser
に無限の HTTP リクエストを処理させることも考えられますが、Ajax リクエストよりさらに複雑になってしまいます。
現代的な Web ブラウザは WebSocket による双方向のリアルタイム通信をネイティブにサポートしています。
WebSocket は双方向かつ全多重の通信チャンネルを、単一の Transmission Control Protocol (TCP) ソケット上で実現する Web テクノロジです。WebSocket の API は W3C により、一方 WebSocket のプロトコルは IETF により RFC 6455 として、標準化が進められています。
WebSocket は元々、Web ブラウザおよび Web サーバにおいて実装されることを想定して設計されていますが、実際はどんな種類のクライアントやサーバでも利用できます。80 番ポート以外への TCP 接続は家庭内ネットワーク以外では管理者によってブロックされていることがよくありますが、WebSocket を使うとこの制限を迂回することができます。つまり、プロトコルのオーバーヘッドと引き換えにはなりますが、通常の TCP 接続と同じような機能を実現することができ、単一の TCP ポート上で複数の WebSocket サービスを多重化させることもできます。
WebSocket は、リアルタイムに双方向通信を行うような web アプリケーションにとっても有用です。WebSocket が実現するまでも、このような双方向通信は Comet チャンネルを使えば実現することができました。しかし、Comet は安定して動作させるのが難しい、また TCP ハンドシェイクや HTTP ヘッダのオーバーヘッドがあるため小さいメッセージを送受信する場合に非効率的であるという欠点がありました。WebSocket は web のセキュリティ要件を落とさずにこのような双方向通信を実現するために開発されました。
§WebSocket を扱う
これまでは、標準的な HTTP リクエストを処理し、標準的な HTTP レスポンスを送信するためには Action
を使っていました。WebSocket はそれと全く異なるので、通常の Action
では扱えません。
WebSocket リクエストを処理するためには、Action
の代わりに WebSocket
を使います。
def index = WebSocket.using[String] { request =>
// Log events to the console
val in = Iteratee.foreach[String](println).mapDone { _ =>
println("Disconnected")
}
// Send a single 'Hello!' message
val out = Enumerator("Hello!")
(in, out)
}
WebSocket
からはリクエストヘッダ (WebSocket 接続を開始するための HTTP リクエストからの。) を参照でき、標準的なヘッダやセッションデータを取得することが可能です。しかし、リクエストボディを参照したり、HTTP レスポンスを返すことはできません。
WebSocket
をこの方法で組み上げる場合、in
と out
の二つのチャンネルを返す必要があります。
in
チャンネルはIteratee[A,Unit]
(A
はメッセージのタイプで、ここではString
になります) で、各メッセージを受信するたびに通知を受け取ります。またソケットがクライアント側で閉じされた場合にはEOF
を受け取ります。out
チャンネルはEnumerator[A]
で、Web クライアントへ送信するメッセージを生成します。このチャンネルにEOF
を送信すると、WebSocket 通信をサーバ側から切断することができます。
この例では、受信した各メッセージを console に出力するだけのシンプルな Iteratee を作成しています。また、メッセージを送信するため、**Hello!** というメッセージを一回だけ送信する単純なダミーの Enumerator も作成しました。
Tip: WebSocket は http://websocket.org/echo.html でテストすることができます。location に
ws://localhost:9000
を設定してください。
次は、入力データを全て捨てつつ、**Hello!** メッセージを送信した後すぐにソケットを閉じる例を書いてみましょう。
def index = WebSocket.using[String] { request =>
// Just consume and ignore the input
val in = Iteratee.consume[String]()
// Send a single 'Hello!' message and close
val out = Enumerator("Hello!") >>> Enumerator.eof
(in, out)
}
次ページ: テンプレートエンジン