未踏ユースに応募したネタ

どうやら1次すら通らなかったという本当に大した体たらくな感じです。がまぁ色々書ける様になったので、色々書き書き(応募に関わらず書いても良かったのか知らないんですけどw)。


実際に私が応募する時に出した提案テーマに関する説明のpdfを上げておきました。

pdf注意!! http://ranha.kerox.info/ranha_youth.pdf

3番までが直接の該当部分なので、そこんとこを読んでもらえると良いと思います。

ブラウザ間直接双方向通信とは何ぞ?

pdfにも書いているのですが、簡単につらつらと。そもそも、このお話自体はちょっと前にはてダでも実は書きました。

ブラウザというプラットフォームの為の基礎技術〜ブラウザ間通信〜 - Yet Another Ranha

実はこれは結構ネタでやったのですが、ちょと考えてみると色々と面白かったのでその後もポツポツと続けていて、そんな所に未踏ユースの話もあったので出してみたという感じです。


話を戻して。ブラウザ間直接双方向通信とは、ブラウザとブラウザで、直接お互いにデータのやり取りをするという事です。まんまですね。


コイツが出来ると何が嬉しいか・・・という話に成ると、Webブラウザをプラットフォームにする、という事を少し考えに入れなければ成りません。
Webブラウザをプラットフォーム(これはWebアプリケーションのプラットフォームという意味を大きくしめますが、それ以外でも問題は有りません)とするというのは、少し前までは、ダウンロードしてインストールして単なるネイティブなアプリケーションとして動かしていた様なプログラムがWebブラウザ上で動く様に成って来たという事を考えると想像が付き易いと思います。


また、それらが実際に台頭して来つつある例としては
http://journal.mycom.co.jp/news/2008/12/02/008/index.html
というWebブラウザを中心に考えるOS Cloud

それに、本当につい先日にリリースされたGoogle Native Clientがそうだと言えるでしょう。あれなんか通常のアプリケーションプラットフォームをWebブラウザに注入したっていう感じですね。
Issues - nativeclient - Native code for web apps - Monorail

Webブラウザをアプリケーションプラットフォームにすると何が嬉しいのか

私の考えとしては、エンドユーザがWebページにアクセスした次の瞬間、アプリケーションが動き始めるという事にあると思います。
このダイナミックな感じは、言い換えると次の様にも成ります。

何を言っているのか分からないと思うが、俺はWebページにアクセスしたと思ったら勝手にアプリケーションをrunしている事になっていた・・・。

気付かない所で、マシンリソースを提供する事が出来る・・・という事になりますね。


マシンリソースを提供すると何が嬉しいのか・・・という話ですが、ちょっと逆に考えてみて「マシンリソースが提供出来る様に成って来た。」と考えるべきだと思います。


以前"ブラウザというプラットフォームの為の基礎技術"にも書いたのですが、これはクライアントサイドスケーラブルっていうやつですね。
確かにサーバとして使うサーバマシンを強化していくというのも1つの手では有りますが、クライアントサイドのマシンも、案外安いにも関わらず中々なスペックに成ってきましたよねーという所に着目した感じの発想です。


で、マシンリソースを提供すると嬉しい様なタイプのアプリケーションていうのは、まぁ分散アプリケーション、特に広域分散に成ります。
なんでWebブラウザでやると嬉しいのかっていうのは、多くのエンドユーザは一々ダウンロードしてくれないって事ですね!!あの人達はインストールはしてくれないんだけど、空いているマシンリソースがある。それを利用出来ないかなーとかいう感じです。


後、私の考えている広域分散なソフトウェアっていうのは、誰しもが簡単に使い始める事が出来る・・・という事だと思うんです。その為にはちょうどWebブラウザが良いのではないか・・・という気がしてならないんですね。


おまけにNaClなんていうのが出て来て、おっググる先生も・・・なんていう事を考えていました。

なんでブラウザ間双方向通信が出来ると嬉しいの??

簡単に言うとP2Pが出来る様になるっていう事ですね。


機能別に分けられたWebページにアクセスした瞬間に、勝手にアプリケーションが走って分散システムを作ろうとする。広域分散な感じなので、ホスト同士で通信したい。
となると、必然的にブラウザ同士で、直接双方向で通信出来ると嬉しくなる訳です。


直接を強調したのは、擬似的に(グローバルIPを持つ)Relay Serverを立てて、そいつを介して双方向で通信する、という事をやればなんとか成るわけです。
が、そもそも直接通信出来るならばRelay Serverを立てる必要も無い、とそういう話になるわけですね。

そもそもこのテーマでやろうと思ったのは => 広域分散システム!

ブラウザの上で動く広域分散システム・・・という事でした。
エンドユーザが何かの機能を持たせたWebページにアクセスした瞬間、分散システムに加担する事に成る。


それはエンドユーザの知る所では無い・・・が事実として動いている。後でネタばらしか何かして・・・おお!こんな事に成っていたのか・・・!!という話に成るんですよね。


Plan9後継Infernoはまさにその側面を持っていると思います。実際に、InfernoはIEの上で動く様にもなっていますね。
http://www.vitanuova.com/inferno/plugin.html


こういう試みがこの先必要になってくるのではないか、なんて考えて、たまらなくなったのでやっぱりブラウザ間双方向通信だろうと。

ブラウザ間直接双方向通信をどうやって実装するか?

ブラウザのセキュリティポリシーをどうする?

NaClは"安全性"を手放さず、ネイティブアプリケーションのパワーを手に入れるという事を求めていました。


今回の場合、最低限許さなければならないのはブラウザの周りでネットワークを使う。Socketのlisten,accept,connectが出来る様にするという事です。


以前の実装ではActionScript3.0をJavaScriptから呼べる様にしていました。これはExternalInterfaceで可能です。


しかしAS3.0にはSocketのlisten,acceptをする事が出来ません。
というわけで、あの時はローカルにProxy-Serverというある意味でのRelayServerを立てていました。

この問題点が何であったかというと、先にエンドユーザを組込むという話をしていましたが、そもそもエンドユーザは多分こんなものを立ててくれないだろう・・・という事で、更に言うとローカルにRelayServerを立てさせると今回は出来ないから仕方なく導入した事によるRelayコストが掛かるのです。


通常のWebProxyServerやReverseProxyの様に理由があって立てたわけでは有りませんし、それらの機能をこのProxyServerに盛り込むには無理が有ります。


なんとかしてWebブラウザ上でSocketの全操作を許さなければいけません。極端な話だと、Webブラウザがサーバになるのです。


これを解決するのは単純に、ブラウザ上で(クロスドメインをも超える)connect,listen,acceptが出来る様にするという事です。これはuntrustedなcodeの不正を防ぐとかでは無く、許可しないとやりようも無いので許可しなければなりません。

さてどうする??

ActionScript3.0は使えません。


どうするか??方法は幾つか有ります。

  1. 新しくWebブラウザを作る
  2. NaClの様に、Webブラウザ毎に力を与える何かを使う。それはActiveXでありNetscape Pluginでありetc
  3. Java Appletを使う。


さて、現在私が実装を行ったのは、JavaAppletを使う方法でした。
次にその事を述べます。

Java Appletの場合

ここでは簡潔に十分に述べる事にします。別のエントリかなんかで詳しく書いた方が良い気もしますので(w


そもそも何故Java Appletを用いるのか・・・という事ですが、皆さんLiveConnect(今はXPConnectの方が良いかも)という技術をご存知でしょうか??


コイツはJavaScript <-> Javaで双方向にやりとりする技術です。
JavaScriptからJavaの関数を呼び出したり、JavaからJavaScriptの関数を呼び出したり・・・なんていう事が出来るわけですね。
さて、何故Java Appletを用いるのかを述べる事にします。簡単な話ですが、Java Appletでは、java.policyというconfigファイルの中でSocketPermissionを弄る事で、Webブラウザがサーバに成ります。


今現在LiveConnectを使う事でJavaScript側からJavaといちゃいちゃ出来るという実装にしています。


なぜJavaScriptなのか・・・という話なのですが、ここは結構重要な話になります。

何故 JavaScript ??

要するにWebブラウザとの親和性が一番高くて、HTMLというリソースをDOMを介して弄れる・・・という事に尽きます。


Webアプリケーションの開発者は、最近はJavaScriptを好んで使うようです。
私としてはSchemeとかHaskellの方が良いんでは無いかなーと思うのですが、今いる人達を取り込む必要性があるので、違和感無くJavaScriptのコードを書けば実はブラウザ間で直接双方向通信出来ちゃった!!という事をやる必要があるだろうな、という事でJavaScriptから色々出来る様にしました。


実際にコードを張ります。

receive = function(mes)//今の所の実装では、Stringが入る事に成っている。
{
  document.my_receive.receive.value += mes +"\n";
}

getNTS1 = function(obj)
{
  obj.initStream();
  obj.setCallBackFunc("receive");//受信時に呼ばれるコールバック関数をregistする。
  obj.startReceive();
  nts.push(obj);
  window.console.log(nts.length);
}

send = function()
{
  for(var i=0; i<nts.length; ++i)
  {
    nts[i].writeString(document.my_input.my_word.value);//皆さんに直接文字列を飛ばす。
  }
  document.my_receive.receive.value += (document.my_input.my_word.value) + "\n";
}

これはチャットシステムのHTMLソースから引っ張って来た物です。


ボタンに対してsendを割り当てているので、何か書き込んでボタンを押すとメッセージがぶっ飛んで相手側のreceive関数が呼ばれて、text-boxに入る・・・という事です。


全体のコードを出すのは今度のエントリぐらいで。


このコールバックモデルにしたのは、Ajaxを使って開発してきた開発者に取っての親和性を考えたものです。


とこんな感じで書ける様になっています。

#余談ですが、receiveに関しては別Threadで走っている為に非同期です。
#そもそもググるChromeの様にマルチプロセスで無いブラウザを使った場合LiveConnect経由でSocket#receiveをすると固まってブラウザがハングした様に見えます。
#タブブラウザFirefoxさんでもブラウザごと固まります。この辺のバッドノウハウについても次回あたり。

その他の方法。

1.ブラウザを作るというのは一番やりやすい方法かもしれませんが、まず面倒くさい。次に、作った所で誰も使ってくれないのではないか。そもそもシステムを作りたいんだから、それをやるのは最終的な手段では無いか・・・などと考えるに至ってまだ作っていません。
なので、この先はどうなってくるか分かりませんが、仮に作るとしてもWebブラウザという形では無い気がします。


2.ActiveXやPluginを使う方法。
これは理想的だと思います。そもそもこれの何が嬉しいかと言うと、JavaScriptが何らかの形で関わる言語処理系を作らなくて済むという事です。
先にも述べましたが、CLispSchemeHaskellが使いたい人はソレで書けば良いんですよ。わざわざJavaScriptを使う必要も無い。
2番目の方法ではこれらの事も可能に成りますし、普通にSocket周りも出来ますね。
なぜPluginを作る方向で最初から作らなかったのか・・・という事ですが、それには幾つか訳が有ります。

  • プラットフォーム毎に書くのが面倒くさい。(NaClを見てやる気になったので、昨日少なくともLeopardで動くNetscape Pluginを書きましたが、結構面倒臭かった・・・。) JavaVMの上で動くJavaAppletなら、JVM Byte Code準備して上げれば終わりですからね。
  • そもそもPluginとか書いた事が無かった。

とこんな感じです。まぁ面倒くさかったというのが1つでした。
それと同時に、やっぱりVMをあちこちで走る様にしているJVM恐ろしい子とか思ったりもしました。


Javaやべぇな・・・!!
ちなみに、JavaだとClojure使ったりScala使ってAppletを作る事が出来ます。JavaFXも出ましたし、Java7も・・・。なんて恐ろしい子っ!!

NATを超える

セキュリティの話は一旦置いておくと、Webブラウザの上でSocketのアレソレが出来る様に成りました!
やったね!!


で、次に"広域分散"だとか"P2P"をやる際につきまとう問題が出てきます。
それはNAT(NAPT)をどうやって超えるかという事です。


これはまた別の記事でNat Traversalについて書こうと思うのですが、簡単に今の所実装している事を紹介します。
また実際にNATを超えています。先に見せた例のJavaScriptWebブラウザ上で双方向通信をNATを超えてやっています。

どうやるの??

今回はUDP Hole PunchingとTCP Hole Punchingを行いました。


手元にあるJavaScriptライブラリではUDPでもTCPでもNATを超える事が出来ます。やりましたね!!

という事で

未踏ユースで提出した書類に、プラスとして今現在出来ている事を追加しながら色々と書いてみました。


これはもうクローズドでも何でも有りませんので、現時点のソースコードなりなんなりを公開しようと思います。
それと、落ちはしましたがこの方向に何かはあると考えているので、この先も進めて行くつもりでは有ります。
(ちなみに、どこで公開すると良いんですかねー。SourceForgeとかかな?)


あと、完全に負け惜しみではありますが、これで落ちたのが残念でした。色々とタイムリーでウハウハなんじゃねーかなとか勝手に思っていたんですが、調子乗ってただけっぽいですね。

その他色々1

以前こんな記事を見つけました。
http://rakuto.blogspot.com/2008/01/2008web.html

ここに書いている

   1. クロスドメイン間のメッセージ通信
   2. マルチスレッドのアプリケーション構築
   3. ストレージへのデータ保存
   4. Serverからのイベントの通知

1はClient to Clientのメッセージパッシング、4はServer to Clientのイベント通知である。
これらの制約を超えれば、ブラウザ上のプラットフォームはますます強力になる。
(エントリより抜粋)

これらは全て出来る様に成りました(3は例外です)。UDP/TCPで。
勿論HTTP over UDP、HTTP over TCPをやればHTTPでも出来ます。


3のストレージへのデータ保存に関してですが、HTML5ではClientSideStorageの話があるのでJavaAppletでローカルリソースへのアクセスを許可させなくても、Plugin使わなくても出来ます。

今年は「P2Pのハイブリッド型アーキテクチャ」に似たアーキテクチャを取るアプリケーションが登場し、
「クライアント間の結びつき」がますます強くなるだろう。
(エントリより抜粋)

なんとか今年中で出来る様に成りました。