リアルタイムAjaxの実装について
現在行っている試みとして、ネットを介して複数のプレイヤーが同じ画面上でゲームをプレイするというようなのを
Ajaxと
PHPだけで実現できないか考えています。人気なオンラインゲームというとモンハンとかそうですが、あれはウェブ上のゲームではないので、技術面で勝手が違うと思うので参考にできません。一方で、何年か前に出たフラッシュゲームで「おらおら学園」という、プレイヤー同士オンラインで殴り合うゲームなんてのがありました。フラッシュはウェブ上で動作するアプリケーションなので、Ajax/JavaScriptでも同じような実装ができるのではないかと考えました。
データをリアルタイムで取得してゲームに反映させるにはどういった方法があるでしょうか。いろいろ調べたところ、いくつか有効な方法がサイトなどに載っていました。
InfoQ: Ajax:プッシュ対プル方式の比較
こちらのサイトによると、代表的なリアルタイムAjaxの実装方法に
HTTP プル、
リバースAjax、
ロングポーリング、
HTTPストリーミングの四つが挙げられています。
さて、まず最初の
HTTP プルというのですが、これはユーザーがウェブページを見るときにいつも行っている操作です。つまり、URLをリクエストしてサーバーがそれを受け取り即座にコンテンツを返すというもの。重要なのは常にクライアント側からリクエストされるという点です。ゲームに参加しているプレイヤーの各状態を把握しているのはサーバー側ですが、
HTTP プルの場合、プレイヤーの状態が更新されてもサーバーからは何もしません。クライアント側が逐次サーバーにリクエストしない限り、自分のブラウザに他のプレイヤーの状態を反映することはできないわけです。仮に他のプレイヤーがその時、全くキャラを操作していなかったとしても、それを自分で知るすべはないので、繰り返しサーバーに問い合わせなければなりません。
Ajaxでこれを実装する場合、たとえばアクションゲームのようなグラフィックの頻繁な更新が行われるタイプだと、コンマ数秒という単位でリクエストしないといけないでしょう。接続のたびにHTTPコネクションを作り直すのでコストがかかる上、サーバーに大きな負荷がかかってしまいます。
次に
リバースAjax方法を見ていきます。これは以下のサイトで詳しく扱っています。
リバース Ajax: 第 1 回 Comet の紹介
Cometという手法は前からあったやり方のようです。通常のHTTP接続はリクエストに対してすぐにレスポンスを出し、接続を切って終了という流れでしたが、
リバース Ajaxではサーバー側で応答を遅延させる方法をとっています。そしてサーバーで情報の更新があったときに、接続を維持していたクライアントに対しレスポンスを返します。いったんレスポンスを返してしまうと接続が切れてしまうので、即座にクライアント側がリクエストして接続を再開します。あとはこの繰り返しです。そのため、
HTTP プルのようにクライアントが頻繁にサーバーへ問い合わせる必要はなく、疑似的にサーバー側からデータをプッシュする仕組みを作ることができるわけです。ただし、サーバー側で頻繁にデータの更新が起こるような環境だと、データをクライアントに送ってすぐ再接続してもらう必要があるので、結果リクエストを高頻度で繰り返すことになり、
HTTP プルの状況とあまり変わらなくなってしまいます。
私の知識が足りないせいか、
ロングポーリングと
リバースAjaxの区別がつきません。が、サーバー側から任意のタイミングでデータを送るという設計は共通していると思います。
さて、最後の
HTTPストリーミングですが、これは自分が採用することにしている手法です。ネット上では扱っているサイトがあまりなかったですが、次のサイトを参考にしました。
PHPとJavaScriptでHTTPストリーミングする話(Transfer-Encoding: chunked編) – id:anatooのブログ
この方法の欠点を先に述べると、ブラウザやサーバーの環境によって使えない場合があることです。
IE6-7は不可能ということになっています。モダンブラウザでも障害がないではなく、バージョンなどによっては使えない可能性があります。
この
HTTPストリーミングのやり方というのは、データを一度に送らずに小出しにしていくもので、その間はずっと接続を維持することができます。サーバーは設定をいじらないとデフォルトで30秒のあいだ接続を維持できるので、一度のHTTP接続で数十秒はデータ送信を繰り返せることになります。接続が切れたら
リバースAjaxと同じように再接続します。
ゲームを例に具体的に見ていくと、クライアントはゲームの中で二通りのリクエストをします。一つは自分のキャラの状態を送るためのリクエスト、もう一つはサーバーから他のプレイヤーの状態を持続的に送ってもらうためのリクエストです。
一つ目のリクエストは、自分のキャラが何らかのアクションをしないかぎり送る必要がありません。二つ目のリクエストは一度送れば数十秒はそのHTTPコネクションを利用でき、接続が切れても再接続するようにスクリプトを書けば問題ありません。これまで見てきた手法に比べると割合経済的に見えます。
大規模なオンラインゲームを想定しているわけではないので、プレイヤーを数人程度に限るようにすれば、レンタルサーバでも何とかいくかもしれません。とりあえず、この
HTTPストリーミングで簡単なサンプルを作ってみる予定です。
-
JavaScript/Ajax, ゲーム Ajax, Comet, HTTPストリーミング, JavaScript, リバースAjax