2012年5月4日金曜日

簡単にwebSocketを試せるJavaプログラムをつくってみました。

WebSocketをやるには、node.jsをいれなくちゃいけない等初心者には、非常に厄介です。

というわけで、初心者でも簡単にWebSocketを体験できるようなアプリをつくりました。
javaアプリなので、JavaRuntimeが必要ですが、最近のPCならまずはいっているでしょう。

やり方
https://sites.google.com/site/javataktod/app
こちらにeasyWebSocketGUI.jarというプログラムがあるので、ダウンロードする。
落ちてきたらダブルクリックすればOK
起動するとこんなウィンドウがでてくる。
これでサーバーの準備はOK
ws://localhost:8080でアクセスできます。

とりあえず起動したら、Google ChromeかSafariで(*1)
http://jsrun.it/poepoemix/rIoc
にアクセス。
すると、webSocket経由でデータの共有が実行されます。

こんな感じでデータ共有できます。
GUIバージョンではないですが、CUIバージョンのプログラムはgithubにあげてありますので興味がありましたら、どうぞ。


注1、ChromeかSafariと指定したのは、jsdo.itのデータがwebkitのみに対応させてあるため。
動作確認そのものは・・
MacOSX 10.6.8の
Google Chrome 18.0.1025.168
Safari 5.1.5
Firefox 11.0
WindowXPの
Google Chrome 18.0.1025.168 m
Firefox 12.0
について動作確認を実施してあります。

2012年5月3日木曜日

websocketについて再度やってみる。その6(windowsのchromeでの動作不良対処しました。)

Windowsのchromeで動作がおかしかった件、原因がわかったので、対処しておきました。



BTW, please take a look at the section 5.1 of RFC 6455.
   A server MUST NOT mask any frames that it sends to
   the client.


とあります。Serverからの送信データはMaskつけちゃだめだよという・・・

chromeのコンソールの部分にもA server must not mask any frames that it sends to the client.
ってでていましたね。

というわけで、webSocketプラグインの方もこれにあわせて修正しておきました。



2012年4月14日土曜日

websocketについて再度やってみる。その5(大量のメッセージをおくったときの挙動)

先にred5用のwebSocketプラグインを書いておりましたが、欠陥をみつけました。

内容は
・複数のメッセージをいっきにおくるとおかしくなる。
・長いメッセージを送るとおかしくなる。
の2点です。

まず前者から。
1つ目。javascriptで次のようなコードをかいてみます。
var ws = new WebSocket("ws://localhost:8080/");
ws.send("a");
ws.send("b");

するとサーバーに送られるメッセージは
たとえばhybi00の場合は
0x00 0x61 0xFF 0x00 0x62 0xFF
というパケットが一気に飛んできます。

僕としては
0x00 0x61 0xFFと0x00 0x62 0xFFが別にとんできてほしかった・・・

現状webSocketプラグインに書いてあるプログラムでは、始めの0x00からみつけた0xFFまでしか調査しないので、後者の命令が無視されてしまうという欠点がありました。
rfc6455でも同様です。

前者は単純な問題なので、さくっと直せる予定です。


さて、後者の方ですがこちらは長いメッセージを送ると発生します。こちらは厄介です。
ws.send("[めっちゃ長い文章(略)]");

さてこれがどうなるか・・・です。

まずhybi00の場合
パケットは次のような感じでおくられてきます。
第1パケット 0x00 データバイト〜
第2パケット データバイト続き〜
第nパケット データバイト続き〜 0xFF

なのでパケットデータをすべて連結して取得しないと正しいデータにならないみたいです。

続いてrfc6455の場合
こちらは、そもそも定義されているのですが・・・
そうはならないみたいです。
定義の仕方によると
0x81 ・・・・

0x01 ・・・・
0x01 ・・・・
と、違うデータがある度に分割されて送信されるとおもっていましたが・・・

実際はこうなりました。
0x81 全体の文字列の長さ データバイト〜
データバイト〜
データバイト〜
という形みたいです。

メッセージとしてうけとるデータが必ずしもパケットの先頭にならないという・・・
なんなんですか・・・この仕様は・・・という形になっていました。

今回のhybi00の動作はsafariでrfc6455の動作の確認はchromeのみ確認済みとなります。
両方ともiMac上での話です。

ではでは〜

2012年4月12日木曜日

websocketについて再度やってみる。その5

jsdo.itにwebSocketを利用したチャットプログラムをぱぱっとおいてあります。
http://jsdo.it/poepoemix/rVsV こんな感じ

んで、本日1日webSocketの挙動、特に3Gではどうなるだの、裏で起動しておくとどうなるだのといったことを調べたのでブログに残しておきます。

利用したのは、手持ちのiPhone4S端末。キャリアはAUです。

まずは3Gの動作について。
・特に問題ありませんでした。3GでもそのままwebSocketはつながるし、問題なくデータのやり取りができました。
・Wifi環境から3G環境に切り替わったときにどうなるかは不明です。

続いてバックグラウンド実行等の話。
・普通にsafariでwebSocketに接続したまま、他のアプリをつかったり、他のタブにいっても、接続が落ちることはありませんでした。
この状態の場合は、webSocketはつながったまま通信をしているようですがjavascript自体は動作せず。バッファがたまっていくみたいな印象でした。
そしてページにもどってきたら、いままでのデータがいっきに吐き出されるといった感じ
このバッファがたまりすぎると、戻ったときにページのリロードがはしってしまうようです。

・続いてスリープ状態にした場合。この場合はwebSocketはいったん切れるみたいです。

最期に、ずっと接続したまま放置したらどうなるか・・・
Safari系はnight build以外では、hybi00で動作するみたいです。
このモードでは、pingについての記述がありません。なので、接続はidle状態になるものと思われます。
僕のつくったRed5のWebSocketプラグインでは、通信がまったくない場合は切断されるようになっているので、ほっとくといつの間にか接続がおちるみたいです。

回避したい場合は、intervalあたりをつかって一定時間ごとに適当なダミーメッセージを送る必要があるとおもいます。
なお、この切れる動作ですが、oncloseのイベントを監視しているのですが、イベントが走らずにきれることがあるみたいです。裏にまわっていて、jsが動作しなかった?疑惑がありますが・・・

rfc6455の方ではpingとpongが定義されているので、ブラウザが勝手に通信してくれるかもしれませんね。調査はしていませんけど・・・

以上、今日調べた結果です。

2012年4月10日火曜日

websocketについて再度やってみる。その4

jsdo.itにwebSocketをつかってテキストチャットをするプログラムをかいてみました。

http://jsdo.it/poepoemix/rVsV

で、やってみてわかったのですが、safari用のhybi00のwebSocketのハンドシェイクが、まだまちがっていたみたいですね。

githubのソースコードかえておきました。

Handshakeの応答データにSec-WebSocket-Locationというのがあるのですが、この応答値と、接続に利用する接続が一致しないと、接続できないのですが、httpでいうところのクエリーの区切り文字が混入して食い違うみたいでした・・・

さっそく直して動作確認しました。

red5で書いてあるから、jsdo.itとwonderFlでデータを共有なんてことしたら、面白いかなw

2012年4月4日水曜日

websocketについて再度やってみる。その3

いろいろいじった結果、red5用のプラグインという形で動作するようになりました。
https://github.com/taktod/webSocketForRed5/tree/master/doc

いつものとおり動作デモも作成してみたので、よかったらためしてみてください。
http://websocket.org/echo.html
このサイトにいく。
ws://49.212.39.17:8080/testにつなぐ。
つながったら適当なメッセージを送る。
同じパスに接続を増やしていくと、同じパス同士メッセージデータを共有できる。
いまのところ、接続元の確認等は、やってません。

これでFlashとWebSocketで同じ内容を共有したりもできるかな。
では、あとは、Webアプリつくってみようかでjqmobiのプログラムで組んでみよう。

2012年3月31日土曜日

websocketについて再度やってみる。その2

データの送受信まわりの動作について調べてみました。
サンプルはあるもののどうも英語の仕様を読み解くのは苦手ですね。
今回もhybi-00とRFC6455の両方について書いておきます。

まずは単純なhybi-00の方。
こちらは単にUTF-8のバイトデータの先頭と最終に0x00と0xffをつければOK
たとえばHelloだとバイトデータが
0x48 0x65 0x6c 0x6c 0x6fになるので
0x00 0x48 0x65 0x6c 0x6c 0x6f 0xff
にして、送信すればOKです。受け取ったデータも同じ。

続いてちょっとややこしいRFC6455の方。
こちらでは、テキストデータ、バイナリデータのほかに、pingフラグ、pongフラグ、切断命令等々あります。またXORによるマスク指定もあります。

まず一番単純なデータから
送信データはHello
0x48 0x65 0x6c 0x6c 0x6f
ヘッダデータが必要なのでそのデータを追加して
0x81 0x05 0x48 0x65 0x6c 0x6c 0x6f
このようになります。
先頭の1バイトはビットに変換すると、
1000 0001になります。
先頭1ビットは今回のパケットで命令がおわるかどうかの指定です。1がはいっている場合はおわる。0がはいっている場合は、あとから別途命令が送られてくる印になります。
次の3ビットは0に予約されています。
後ろの4ビットはデータが何であるかの指定です。
1:テキスト 2:バイナリ 3-7は将来に予約 8はコネクションを閉じる 9はping Aはpong、B-Fは将来に予約となっています。
よって0x81は今回の通信で終了するテキストデータ
0x01はあとで別のデータが追記されるテキストデータ
0x82は今回の通信で終了するバイナリデータといった具合になります。
次の1バイトはマスクフラグとメッセージの長さになります。
例では0x05になっています。ビットに変換すると
0000 0101となります。
先頭の1ビットが0になっているので、今回はマスクはなし。のこりのビットデータによるとデータが5になるので、後ろの5バイトがメッセージデータということになります。
後ろの5バイトの0x48 0x65 0x6c 0x6c 0x6fがUTFコードでHelloという文字になりますので、このデータは[今回の転送のみで完了するデータのマスクなし、5バイトのデータHello]
ということになります。

続いてあとで別のデータが追記される場合のサンプル
0x01 0x03 0x48 0x65 0x6c
0x81 0x02 0x6c 0x6f
こんな感じになります。
まず始めのデータ

0x01 0x03 0x48 0x65 0x6c
1バイト目が0000 0001になっているので、今回のメッセージで完了しないデータかつ、テキストデータという指定になります。
2バイト目、0000 0011になっているので、マスクはなし。長さは3バイト
んで、うしろの3バイトをみるとHelになっています。
2つ目のデータ
0x81 0x02 0x6c 0x6f
1バイト目が1000 0001になっているので、今回のメッセージで完了する。かつテキスト
2バイト目が0000 0010になっているので、マスクフラグはなし、長さは2バイト
んで、うしろの2バイトをみるとloになっています。
前のデータとあわせるとHelloというデータになります。

続いてマスクがある場合の動作
例Hello
0x81 0x85 0x37 0xfa 0x21 0x3d 0x7f 0x9f 0x4d 0x51 0x58
こんなデータになります。
まず先頭1バイトですが、1000 0001となっているので、今回でおわりのテキストデータとなります。
次に2バイト目 1000 0101となり、マスクビットが設定されている(先頭の1ビット目)でサイズは5バイトとなります。
そこから続く4バイトはマスク用の値となります。
0x37 0xfa 0x21 0x3dが対象です。
最後の5バイトがHelloを表しています。
0x7f 0x9f 0x4d 0x51 0x58
で、復号の仕方なわけですが、XORでマスク用の値と掛け合わせてやればOKです。
0x7fは0x37と、0x9fは0xfaと・・・という順番で組み合わせていき、4つ目までおわったらまた始めに戻ります。なので5文字目の0x58は0x37と掛け合わせます。
0x37とx07fはビットにすると
0011 0111 (0x37)
0111 1111 (0x7f)
xorにかけてやると
0100 1000 (0x48)になり。これはHを表します。

どうように0xfaと0x9fでは
1111 1010 (0xfa)
1001 1111 (0x9f)

0110 0101 (0x65)になりe

0010 0001 (0x21)
0100 1101 (0x4d)
0110 1100 (0x6c) → l

0011 1101 (0x3d)
0101 0001 (0x51)
0110 1100 (0x6c) → l

0011 0111 (0x37)
0101 1000 (0x58)
0110 1111 (0x6f) → o
というわけで、Helloとなるわけです。

以上でwebsocketで送信されてくるデータをUTF-8の文字に変えたり元に戻したりできるようになりました。