Flex(Air)でWebSocket
FlexでWebSocketやってみました。Airです。
FlexSDK4.6、Jetty8、Scala2.9.1finalです。
・サーバ
JettyでのWebSocketのTipsは、色々あります。
ただ、Jettyのバージョンによって、サンプルの実装方法が違ったり、
Jetty/Feature/WebSockets - Eclipsepedia
これにあるように、組み込み型以外で、使うのはオススメしないよ(?)的な記述だったり、
何が正解かを判断するには、なかなか難しいところです。(自分だけかもしれませんが・・・)
import scala.collection.mutable.Set import org.eclipse.jetty.websocket.WebSocket.Connection import org.eclipse.jetty.websocket.WebSocket import org.eclipse.jetty.websocket.WebSocketServlet import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletResponse class hogeWebSocketServlet extends WebSocketServlet { private val _conns = Set.empty[hogeWebSocket] override def doGet(req:HttpServletRequest, res:HttpServletResponse) = { } override def doPost(req:HttpServletRequest, res:HttpServletResponse) = { push("Message from the POST") } def doWebSocketConnect(arg0: HttpServletRequest, arg1: String): WebSocket = { return new hogeWebSocket } def push(message:String) { for (c<-_conns) { c._conn.sendMessage(message) } } class hogeWebSocket extends WebSocket with WebSocket.OnTextMessage { var _conn:Connection = _ def onOpen(conn:Connection) { _conn = conn _conns += this } def onClose(closeCode:Int, message:String) { _conns.remove(this); } def onMessage(message:String) { for (c<-_conns) { c._conn.sendMessage("server got message. return this message") } } } }
Scalaで記述しています。
基本的な形は、WebSocketServletを継承したServletを作り、
doWebSocketConnectで、WebSocket,WebSocket.OnTextMessage(テキストメッセージ),WebSocket.OnBinaryMessage(バイナリメッセージ)
を継承したクラスを返却します。
Servletでは、そのWebSocketのインスタンスを保持する形です。
pushというメソッドを作っていますが、WebScoketを行う上では、
クライアントからメッセージを受信して、サーバから返信もよくあるパターンだと思いますが、
クライアントからのメッセージ受信以外で、サーバから返信したい場合もよくあると思います。
(DB更新したらメッセージプッシュとか)
その場合は、このServletにPOSTするか、別Servletからforword,includeするとプッシュしてくれます。
メッセージの内容は、requestにsetAttribute()しておくのが楽でしょうか。
・クライアント
Flashでは、Socketや、XMLSocketのサポートがありますが、WebScoket自体のサポートはまだないようです。
ただ、さすがFlash、開発者が多いためか、ライブラリを自前で作成してる方がいます。
一つは、ソーシャルゲームのUI開発はAdobe AIR/Flashが主役になるか〜「ADC MEETUP 04 Social Gaming」レポート(3/4)- @IT
でも紹介されているwebsocket-as https://github.com/y8/websocket-asです。
これ使い方は非常にシンプルで、いいなーと思ったのですが、残念ながらSSL非対応(wss)です。
WebScoketは、以前セキュリティホールが発見されたりと、まだ注意が必要だと思っているので、
個人的には、SSLで実装したく、websocket-asは使いませんでした。
もう一つは、AS3WebSocket GitHub - theturtle32/AS3WebSocket: ActionScript 3 WebSocket client implementation for the final WebSocket Draft RFC6455です。
こちらSSL対応です。githubからcloseして、ソース見たところ、SSL大変ですね・・・。感謝感謝。
今回は、Airなので、AS3WebSocketを使いましたが、
もしFlexならば、JavaScript経由した方が良いのでは思ったりします。
web-socket-js GitHub - gimite/web-socket-js: HTML5 Web Socket implementation powered by Flash
AS3WebSocketのUsage Exampleな感じで実装すればOKです。
自分がハマったのは、
WebSocketEvent.CLOSED
WebSocketErrorEvent.CONNECTION_FAIL
のイベントがdispatchされた場合に、再接続したかったので、
closeした場合に、websocket.connect()してみました。
すると、エラーが連発されます。
close(fail)→connect→close(fail)→connect→close(fail)→・・・な感じです。
強制的にサーバ(Jetty)を落として、実験していたのですが、サーバが復帰しても、エラーが発生し続けます。
なんとなくですが、サーバが落ちてる場合は、connectとclose(fail)を繰り返し、
サーバが復帰したら、connext→openをイメージしてたのですが、そうはいきませんでした。
対応としては、
ソース見ると、connectは基本的には、Scocketのconnectを実行しているだけなので、
インスタンスをそのまま使いまわすと、connext以外のイベントハンドラが実行されたりします。
ですので、乱暴かもしれませんが、再接続の際は、websocketをnewするとうまくいくようです。もちょっとソース見てみよう。
まだ、WebSocket触り始めたばかりなので、雰囲気しか掴めてませんが、
WebSocketのバイナリメッセージを試したら、ウェブの未来が垣間見えた: Tender Surrender
このような感想を見ると、可能性はたくさんあるように思います。
正直、自分が作ってるアプリなんかは、全部WebScoketでいんじゃねと思っちゃうくらいです。
まずはシンプルに使ってみて、様子見です。