daily gimite RSSフィード

2009/08/13

[js][html5][websocket] web_socket.js - HTML5のWeb SocketをFlashを使って実装 23:13

HTML5のWeb Socketを、Flashの力を借りて実装してみました。

gimite / web-socket-js - GitHub

Web SocketはHTML5に入る(予定の?)機能で、JavaScriptから生のTCP Socketに近いもの*1を使えるようにしよう、というものです。

2009年11月頃にChromeの開発版で実装されましたが、ほかのブラウザでは未実装です。このライブラリを使うと、すべてのブラウザで(Flashが入っていれば)Web Socketが使えるようになります。

使い方はこんな感じです。


  // おまじないその1: JavaScriptライブラリの読み込み
  <script type="text/javascript" src="swfobject.js"></script>
  <script type="text/javascript" src="web_socket.js"></script>
 
  <script type="text/javascript">
    
    // おまじないその2: Flashファイルの場所を教える
    WEB_SOCKET_SWF_LOCATION = "WebSocketMain.swf";

    // あとは本物のWebSocketと同じ
    var ws = new WebSocket("ws://example.com:10081/");
    ws.onopen = function() {
      ws.send("Hello"); // メッセージの送信
    };
    ws.onmessage = function(e) {
      // メッセージの受信
      alert(e.data);
    };
    ws.onclose = function() {
      alert("closed");
    };
 
  </script>

注意点として、Flashのソケット機能を使うので、サーバ側に(Flash経由でのソケットのアクセスを許可するための)ソケットポリシーファイルというものが必要です。後述のweb-socket-rubyを使う場合は、web-socket-ruby自身がソケットポリシーファイルを提供するので、何もする必要はありません。が、以下の場合は手動でソケットポリシーファイルを設置する必要があります。

  • すでに843番ポートにソケットポリシーファイルを設置している場合。843番ポートのものが優先されるので、こちらにWeb Socketのポートへの接続を許可する設定を追加する必要があります。
  • web-socket-ruby以外のWeb Socketサーバの実装を使う場合。Flashのソケットポリシーファイル - namespace gimiteの「おすすめの設置方法」に従って設置するのがおすすめです。

クライアントだけ書いてもテストできないので、ついでにRubyでWeb Socketサーバを作るライブラリと、それをテストするために、RubyでWeb Socketクライアントを作るライブラリを書きました。

gimite / web-socket-ruby - GitHub

そんなに仕様をまじめに読んだわけではないので、一部仕様と違っていたり、未実装だったりするかもしれません。

2009/8/29追記: web-socket-rubyがソケットポリシーファイルを提供するようになったので、文面を修正しました。

2009/12/2追記: Chromeの開発版でWeb Socketが実装されたので、文面を修正しました。

*1:近いもの、であって、TCPそのものを自由に使えるようになるわけではありません。

makotoimakotoi 2009/12/02 08:01 こんにちは。
もともとnode.jsでのストリーミングの方法に悩んでいたところ、他の方からweb-socket-jsのことを教えていただき(http://groups.google.com/group/nodejs/browse_thread/thread/d4195ad891dcddfd)ここまでたどりつきました。

web-socket-ruby のサンプルを試したところ普通に動いたのですが、web-socket-jsのsample.htmlをREADMEファイルを参考に試したところうまく私の環境(OSx Snow Leopard)では動かないようです。

1 ruby lib/web_socket.rb server ws://localhost:10081
2. sample.htmlを開いても”onopen”がブラウザ上に表示されませんでした(FireBug上からnetwork通信が行われた形跡もありませんでした)。
3.FireBug上から色々オブジェクトをつついてみたのですが、エラーばかり出てきます。

ws
Object readyState=0 bufferedAmount=0
ws.send('1')
INVALID_STATE_ERR: Web Socket connection has not been established
WebSocket.__flash.create("ws://localhost:10081/")
TypeError: WebSocket.__flash is undefined
WebSocket.__flash = FABridge.webSocket.root();
TypeError: FABridge.webSocket is undefined

4. 一応Flashのソケットポリシーファイルが自分のマシンに設定されていないことを確認するために/etc/servicesファイルも調べてみたのですが、flashpolicyに該当する文字はありませんでした。



デバッグのためにほかに調べる箇所などをご指摘していただけると大変うれしいです。
よろしく御願します。

GimiteGimite 2009/12/02 09:45 Flashの埋め込みに失敗しているように見えますねぇ。思いつくポイントとしては

- FABridge.js, swfobject.js, web_socket.js, WebSocketMain.swfはきちんと同一ディレクトリにあって、ブラウザからアクセスできるか?(パーミッション等)
- そのブラウザでほかの普通のFlashはちゃんと再生出来るか?
- Flash Playerのバージョンは? (こちらでは10で動作確認してます。9でも動くんじゃないかと思いますが…。)
- web_socket.js:120のFABridge.addInitializationCallbackは呼ばれているか?そこで渡されているコールバックは呼ばれているか?
- web_socket.js:107の座標を+10, +10とかに変更して、きちんと画面上に小さい四角が表示されるか?その四角を右クリックしたときに「ロードできません」とか書いてないか?
- Debugger VersionのFlash Playerをインストールして、Flashのエラーがでてないか調べる。
http://www.adobe.com/support/flashplayer/downloads.html
のDebugger Versionsのところからダウンロードできます。

ぐらいでしょうか…。

makotoimakotoi 2009/12/02 18:36 アドバイスありがとうございます。早速教えていただいたポイントを試してみます。

makotoimakotoi 2009/12/02 18:51 うまく動きました!!
"Open sample.html in your browser."とあったので、単純にファイルをブラウザ上で開いていたのですが、Flashを実行するためにはsample.htmlをweb server上からアクセスしないと駄目でしたね。
以下のようなミニサーバスクリプトを同一ディレクトリから立ち上げ(ruby foo.rb),http://localhost:10080にアクセスしたところうまくできました。
http://gist.github.com/247090
ありがとうございました。
次はnode.jsと組み合わせてストリーミングができるか試してみます。

GimiteGimite 2009/12/02 20:23 たしかにローカルファイルとして開くとFABridgeがうまく動かないみたいですね。READMEに書いておきます。

makotoimakotoi 2009/12/03 09:01 余談ですが、node.js上でwebsocketのサーバーサイドを実装したhttp://github.com/gimite/web-socket-jsというのを試してみたのですが、非常に簡単にストリーミングが出来ました(例:http://gist.github.com/247752 ただループしているだけのサンプルです)。最新のChromium上でしかまだ動作確認していませんが。 web-socket-jsからに関しては目下OSxかnode.jsからどうやってFlashPolicyファイルをリターンさせるか今調査中です。ご参考になれば幸いです。

GimiteGimite 2009/12/03 09:22 ソケットポリシーファイルは843番ポートに置く方法と、実際の通信を行うポートから返す方法の2つがあるのですが、たぶん843番ポートにおく方が(既存のサーバをいじらなくて済むので)簡単だと思います。
http://gimite.net/pukiwiki/index.php?Flash%A4%CE%A5%BD%A5%B1%A5%C3%A5%C8%A5%DD%A5%EA%A5%B7%A1%BC%A5%D5%A5%A1%A5%A4%A5%EB
に説明があります。

makotoimakotoi 2009/12/06 08:17 結局、通信を行うポートから返す方法をサーバに実装しました(http://github.com/makoto/websocket-server-node.js/commit/4b8abc1669de32db2edd2796e0c318ef2ff6fa08)
それをつかって自分のマシンのリソース状況をリアルタイムに中継するウェブアプリを作ってみました。
http://github.com/makoto/node-websocket-activity-monitor
おかげさまでChromium以外の普通のブラウザでも動いています。
ありがとうございました。

makotoimakotoi 2010/07/26 23:06 お久しぶりです。いつもweb-socket-jsを重宝させていただいております。

一つ質問なのですが、WebSocketMain.swfファイルはhtmlファイルと同じドメイン上に設置されないと駄目なのでしょうか?現在html,swfファイルをドメインA, jsファイルをドメインB, websocketサーバをドメインCに設置しているのですが、swfファイルもドメインBに移そうとしたところ、websocketサーバにコネクトできなくなりました。 (http://stackoverflow.com/questions/452415/how-to-make-cross-domain-communication-between-javascript-and-flash)にあるようにSecurity.allowDomain("*")をasファイルに含めたら大丈夫かと思ったのですが、コンパイルでエラーが出てしまうようです。

[flash-src (master)]$ ./build.sh
Loading configuration file /usr/local/flex_sdk_3.5/frameworks/flex-config.xml
/Users/makoto/src/web-socket-js/flash-src/com/hurlant/util/Base64.as(143): col: 51 Error: Type was not found or was not a compile-time constant: Vector.

public static function InitEncoreChar() : Vector.<int>
^

/Users/makoto/src/web-socket-js/flash-src/com/hurlant/util/Base64.as(166): col: 51 Error: Type was not found or was not a compile-time constant: Vector.

public static function InitDecodeChar() : Vector.<int>

もしなにかご存知でしたら教えていただけると大変たすかります。
よろしく御願します。

GimiteGimite 2010/07/26 23:36 最近Flex 3 SDKではコンパイルできなくなりました。Flex 4 SDKで試してみてください。

現状では、SWFファイルはHTMLファイルと同じドメインに置かないと駄目だと思います。その辺はよく分かってないのですが、Security.allowDomain("*")すれば大丈夫なのかもしれません。

makotoimakotoi 2010/07/28 00:14 お返事ありがとうございます。Flex 4SDKにしたらすんなりコンパイルできました。Security.allowDomain("*")を含めてコンパイルしたのですが、あまりうまく行っていません。ひょっとしたらallowScriptAccess: "always"をswfobject.embedSWFのオプションで指定しなければいけないかもしれません。現在色々試行錯誤中ですので、もしうまく行ったらまたご報告します。

makotoimakotoi 2010/08/09 17:26 追記ですが上の二つの設定でCross Domainはうまくいきました。ただ次に別の問題にぶちあたってます。wssフォールバックなのですがCertificate がSelf CertifiedとベンダーなどでCertifyしたものとでFlashのHandshakeが微妙に異なるようで、Certifyしたものだと接続が切断されてしまうようです(普通は逆なんですけれど)。sslのパッチを送ったJoelからgithub上でいろいろアドバイスもらったのですが、結局原因分からずじまいでした。なにか心当たりがあれば教えていただけるとありがたいです。

あと話が変わりますが、月末に「WebSocket BOF」という会が東京で開催されます(私も参加します)。 http://tweetvite.com/event/WSBoF もし近郊にお住まいでしたらぜひご参加おまちしております。

GimiteGimite 2010/08/09 23:41 wssは実は自分では一度も試してないので、すいませんがよく分かりません…。

makotoimakotoi 2010/08/09 23:52 お返事ありがとうございます。こちらでも何か分かればまたご報告いたします

GimiteGimite 2010/08/22 17:02 wssの件、たぶん直りました。詳細は http://github.com/gimite/web-socket-js/issues#issue/28 を見てください。