で、そういえば昔スコアサーバの実装の説明を書こうとしたなぁ…と思い出して発掘してきました。以下昔の文章。
http://shinh.skr.jp/psyno/scoreserv.cgi
この手の機構はUIの実装が面倒なだけで、コア部分自体は極めて簡単です。業務用でもネットランキング当たり前の時代に常時接続をほぼ仮定しても問題ないフリー/同人ゲームでこういうのが無いのは寂しいことだなぁ…とか思って試しにやってみたというような感です。 id:isshikiさんが「案外実装の仕方がわからないのではないか」とおっしゃっていたこともあり、今回の手法をご紹介してみることにしました。ごくごく普通ですが。
基本的にHTTPでやりとりします。全体に低速回線を考慮してやりとりするデータが小さめになるようにしています。
クライアント側は D言語です。通信部は別スレッドで動かし、エラーが出たらログを残しつつそのスレッドとサヨナラします。通信処理でゲームが落ちるのはすごくイヤ、かといってマジメに通信処理を実装するのも面倒、を両立させる設計です。
サーバ側は二つの Ruby スクリプトで、登録部が134行、表示部が81行です。データの保持は Ruby の Marshal を使っています。
- 登録
HTTP の POST メソッドで行います。通常のステータスライン、必要なヘッダに加えて、 body部でリプレイデータをそのまま流し込みます。
POST http://shinh.skr.jp/hoge/regist.cgi HTTP/1.0 Host: shinh.skr.jp Content-Length: <リプレイデータのサイズ> <リプレイデータ>
リプレイデータは
key1: value1 key2: value2 key3: value3 <入力のデータをRLEで圧縮したもの>
となっていて、 HTTPの構造を模していますが、これは一応、普通のブラウザでは送れないデータです。サーバは key から必要な情報を取り出し、登録するならリプレイデータを保持し、 Marshal のデータを更新し、次で述べるスコア一覧用のキャッシュを再生成します。
- 一覧
スコア一覧用のキャッシュを HTTP の GET で拾って来て適当にパーズして表示します。データを小さくするため、ムダなヘッダの情報は入っていません。そのキャッシュは以下のようなものです。
http://shinh.skr.jp/psyno/scores_normal.txt
これは実際にpsynoが拾ってきているデータで、このタイミングでは CGI の実行は発生しません。
- 取得
リプレイデータもごく普通に HTTP の GET で拾ってきているだけです。ローカルに保持するため、二度目以降は再取得を行いません。
このタイミングでも CGI の実行は発生しません。
- 表示
掲示板程度のものが作れる人なら問題なく作れるでしょう。
- 【ここから】結局【2006.01.07追記】
工夫した点は、たぶん
- データは圧縮とかで適度に小さく
- 手軽に使えるプロトコルとしてHTTPを利用
- 登録処理は、一応formでは送れないデータにしておく(手軽なチート対策)
- でも基本的には無防備
- 取得動作は基本的にキャッシュを読むだけ(負荷少なく)
くらいで、まぁ常識的な範囲かと。参考になれば幸い。以下はサーバのソースコードです。当時公開しなかった理由は忘れましたが、この文章やらソースコードやらを見れば攻撃は簡単な気がします。まぁできればやめて下さいな。