MASATOの開発日記


前の開発日記 次の開発日記 一覧

2002/10/29

Tomcat + AxisでWebサービスのサーバーサイド、C#でクライアントサイドを作成していますが、 まだ、SOAPを自分自身で扱ったことがありません。 クライアントでは.NET Frameworkクラスライブラリの関数を呼び出すと、 どこかでSOAP要求メッセージに変換されてサーバに送られ、 Axisのどこかでそれを解析してJavaのメソッド呼び出しとしてサーバのプログラムが呼び出され、 メソッドの返り値は、AxisのどこかでSOAP応答メッセージに変換されてクライアントに送り返され、 クライアントの.NET Frameworkクラスライブラリがそれを普通の関数の戻り値として返すようです。
つまり、送る方は、C#の記法に則って関数を呼び出し、戻り値を得る。 受け取る方は、Javaの記法に則ってメソッドが呼び出されるので、値を返すようになっています。
開発者は、どこでSOAPが使われているか意識する必要がなさそうです。

WSDLは、自動生成はされるのですが、ちょっとトラブルがあったため、 どのようなWSDLが生成されるか確認するという作業を行っていましたので、 まだ意識しないというわけにもいきません。 しかし、これも、開発ツールの操作性や安定性や機能が向上していけば、 WSDL?何それ?という状態でもWebサービスは開発できるようになっていくでしょう。

しかし、簡単に開発できてしまうと、「Webサービスが開発できる技術を持っている」ということに 利点がなくなるので、それはそれで少し残念な気もします。

ネットワークゲームにおいて送受信するデータの内容(2)

前回の続きです。

その結果どうなったかという情報を送る考えをすっぱり捨て、 何が起こったかという情報だけを伝えるようにし、その結果どうなったか という情報は、各クライアントで計算するようにしました。
「Aの魔法により、BのHPに30のダメージと毒を与えた」という情報だけを送り、 「AのMPが90になり、BのHPが70になり、Bが毒状態になる」という情報は、 各クライアントで計算を行って求めてもらいます。

結果、次のようなメリットがありました。

もちろんデメリットもありました。

計算ミスに関しては気をつけることにしました。特にrand()のような擬似乱数を使うと、 他のクライアント上の計算結果と異なるものがもたらされるので、その点に注意しました。
そして、メリットの恩恵を受け、開発が一歩進みました。

しかし、このゲームは最初はスタンドアロンでしかプレイできないように開発するので、 この方法が本当に有効かどうかが問われるのは、ネットワークに対応しようとした時であり、 それは当分先のことでしょう。結局「やっぱだめだった〜」と叫んで設計をやり直すことになるかもしれませんね。

最初からこのように設計していれば良いという話もあるかと思いますが、いやまったくごもっともですね(^^;)

ファイルを用いた共有ロック方法

環境Java2 1.4 Standard Edition

今回は、複数のプロセス間の共有ロックの方法についてです。 1つのプロセスにおけるスレッド間の共有ロックは、synchronizedでは実現できません。 synchronizedでは排他ロックしかできないためです。

コードとしては以下のようになります。前回の排他ロック方法と比べてlockメソッドの引数が少し違うだけです。

import java.io.*;
import java.nio.channels.*;

// 中略

    try {
      File file = new File("ファイル名");
      FileChannel channel = new RandomAccessFile(file, "rw").getChannel();
      FileLock lock = channel.lock(0, Long.MAX_VALUE, true);
      // 危険領域となる処理
      lock.release();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

// 後略

前回の排他ロック方法に出てきた"ファイル名"を、上記のコードの"ファイル名"と合わせれば、 共有ロックと排他ロックを連携して使うことができます。

ここから先は共有ロックと排他ロックをどう使うかの説明になります。一般的な情報処理技術の話です。

共有ロックと排他ロックは、以下のような関係にあります。

もし、共有ロックしか使わなかった場合、共有ロックは何の役割も果たしません。 なぜなら、あるプロセスが共有ロック中に他のプロセスが共有ロックできるので、 すなわちまったく排他制御されていないということになるからです。

よって、共有ロックは排他ロックとセットで使わます。 例えば、ファイル書込み中は排他ロックされ、ファイル読込み中は共有ロックされる、というような場面で 用いられます。 書込み中に読込むと、途中までしか書込まれていないファイルを読込むことになって、 正しく読めない場合がほとんどでしょう。 読込み中に書込んでも、同様の問題が発生する可能性があります。 書込み中に書込むのは、まず確実にファイルの破損を招き、悲惨な結果になりそうです。 しかし、読込み中に読込むのは何ら問題がありません。
そして、読込めるならすぐ読込んだ方が、アプリケーションとしてのレスポンスも良くなります。 排他ロックでは、この「読込み中の読込みはロックされない」ということを実現できませんが、 排他ロックと共有ロックを両方使うことにより、実現できます。

簡単ですが、最後に排他ロックと共有ロックを使った例を挙げます。

Dataクラスのメソッドoperationは、ファイルを読込み、加工して書込む処理をします。 メソッドreadは、ファイルを読込んで内容の一部の文字列を返す処理をします。 operationやreadは複数のプロセスから呼ばれるものとします。

import java.io.*;
import java.nio.channels.*;

class Data
{
  public static final File file1 = new File("file1");
  public static final File file2 = new File("file2");

  public void operation()
  {
    try {
      FileChannel channel = new RandomAccessFile(file1, "rw").getChannel();
      FileLock lock1 = channel.lock();
      // ファイル読込み
      // 読込んだデータを加工
      FileChannel channel = new RandomAccessFile(file2, "rw").getChannel();
      FileLock lock2 = channel.lock();
      // ファイル書込み
      lock2.release();
      lock1.release();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
  public String read()
  {
      FileChannel channel = new RandomAccessFile(file2, "rw").getChannel();
      FileLock lock2 = channel.lock(0, Long.MAX_VALUE, true);
      // ファイル読込み
      lock2.release();
      // 読込んだデータの一部をreturnする
  }
}

operationメソッドが同時に実行されると、加工処理が無効になってしまう可能性があるので、 operationメソッド全体はfile1を用いて排他ロックを行います。 readメソッドは、operationメソッド中のファイル書込みの部分と同時に実行されると問題あるので、 その部分だけに絞り、共有ロックと排他ロックを用いて排他制御を行っています。
このように細かく排他制御することにより、データファイルを保護すると同時に高速なレスポンスを 実現しています(ホントか!?)

(2003/07/24) 例外処理を細かく記述した。

前の開発日記 次の開発日記 一覧