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でいんじゃねと思っちゃうくらいです。
まずはシンプルに使ってみて、様子見です。