Flash部品(SocketJS)を使って,JavaScriptでのソケット通信を実装した顛末.
JavaScriptとFlashでSocket通信
思うところがあって,JavaScriptから連鎖ゲームのサーバに接続したくなった.
HTTPではなく,Socket通信だ.
1.SocketJS
JavaScript単体ではさすがに無理なので,どうすればよいかと調べてみると,
JavaScriptからSocket通信するためのFlash部品が見つかった.
最近はメンテされていないのか,ダウンロードしようとしてもリンク先が切れていたので,
ブラウザキャッシュに残っていたsocket.swfを使わせてもらうことにした.
これを使うと,任意のホスト,ポートに接続してデータ送信できるようだ.
受信は非同期になっていて,データを受信するとそのタイミングで特定の名前のfunctionが呼び出される.
この時の呼び出し引数で,受信データを受け取れる.
機能的には問題無さそうだ.
2.Flashのサーバセキュリティポリシー
ところが,これを使ってサーバにデータを送信すると,なぜか
というわけの分からないデータがサーバに送られてきて,そこで止まってしまう.
調べてみると,
最近のFlashでソケット通信をすると,必ず最初にこのリクエストが飛ぶようだ.
そしてサーバ側では,これに対してセキュリティポリシーファイルというものを返さないと,
実際の通信を始めてくれないようだ.
それではどのようなセキュリティポリシーファイルを作ればよいのかだが,
考えるべきことは,セキュリティポリシーファイルを
- ソケット通信サーバ本体で出力するのか,
- ポリシーファイル出力用の専用サーバをTCPポート843で立ち上げるのか
ぐらいだと思う.
しかしこの選択については,2.の方が良さそうだ.理由は,
- ソケット通信サーバ本体で出力する場合は,セキュリティポリシーのリクエストが来た場合と通常のリクエストが来た場合で全然違う処理をやることになるので,サーバの実装がいまいちすっきりしないと思う
- Flashは,ソケット通信開始時にまず843ポートを問い合わせて,駄目だった場合3秒後にソケット通信サーバのポートに接続するので,ポート843で対応しない場合は3秒のタイムラグが生じてしまう
ということで,うちでは専用サーバを立ち上げることにした.
ポリシーファイルの書き方
ポリシーファイルはXMLで,DTDはこれ.
カモランドのポリシーファイルの内容
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<site-control permitted-cross-domain-policies="master-only"/>
<allow-access-from domain="kamoland.com" to-ports="*"/>
</cross-domain-policy>
- permitted-cross-domain-policies
- セキュリティポリシーファイルを出力する方式
方式 | 設定値 |
専用サーバを立ち上げて出力する場合 | master-only |
ソケット通信サーバで出力する場合 | all |
- domain
- swfファイルを配置するドメイン
- to-ports
- Flashからのソケット通信を許可するポート.うちではサービス提供ポートを隠すために「*」にしている
ポリシー送信専用サーバプログラムの書き方
これは,以下の資料を見るのが確実.
ここでSample scriptsとして,PerlとPythonで書かれたサーバをダウンロードできる.
要は,
のリクエストが来たら,上記のポリシーファイルの内容を出力すれば良い.
3.FlashのNULL区切り通信という仕様
このサーバをポート843で動かすことで,めでたくソケット通信サーバ本体には
が来なくなった.しかしサーバが送信したレスポンスを,クライアント(JavaScript+Flash)側で受信できないという問題が起きた.
それで調べたところ,レスポンスの最後にNULLを付けていないのが原因だった.
NULLを付けると,クライアントで無事に正しく受信できた.
NULLは,perlだとこんな感じで作れる.(上述の,ポリシー送信用サーバサンプルより)
$NULLBYTE = pack( 'c', 0 );
ふぅ,ここまで来てようやく,クライアント(JavaScript+Flash)とサーバ(Perl)間のSocket通信が完全動作した...
しかし通信できたとはいえ,既存の連鎖ゲームサーバは改行文字を通信の区切りに使っているので対Flashには使えず,
結局対Flash専用に別のサーバプログラムを作るはめになってしまった...orz