ASH | サーバ | セキュリティ | Linux | FreeBSD | DB | Web | CGI | Perl | Java | XML | プログラム | ネットワーク | 標準 | Tips集

RMIについて

RMIとは

 RMIとは、Remote Method Invocationの略で、別のホストのJavaオブジェクトのメソッドを呼び出すための通信手段です。 RMIを使うと、通信を意識せずに、Javaのサーバ、クライアントプログラムを作成することができます。

RMIの構成

 RMIでは、クライアント側にスタブモジュール(Stub)を用意し、サーバ側にスケルトンモジュール(Skel)を用意する必要があります。 これらのモジュールは、rmicコマンドで作成できます。
 動作の流れとしては、クライアントがサーバのメソッドを呼び出すと、スタブのリモートインターフェイスが、メソッドの引数をネットワークのストリームに変換してくれます。 このストリームを、サーバ側のスケルトンが受け取り、サーバのリモートオブジェクトのメソッドを呼び出します。
 また、返却値は、サーバのリモートオブジェクトから、スケルトン、スタブによって、クライアントに戻されます。

 +-----------------+              +-----------------+
 |  +-----------+  |              |  +-----------+  |
 |  |  Client   |  |              |  |  Server   |  |
 |  +-----------+  |              |  +-----------+  |
 | 返却値↑        |              |       ↑メソッド|
 |       │メソッド|              |       │  引数  |
 |       ↓  引数  |              | 返却値↓        |
 |  +-----------+  |  ストリーム  |  +-----------+  |
 |  |   Stub    |<------------------>|   Skel    |  |
 |  +-----------+  |              |  +-----------+  |
 +-----------------+              +-----------------+

 RMIの名前解決には、RMIレジストリが使われます。 RMIレジストリには、bindメソッドで登録し、lookupメソッドで参照します。 RMIレジストリを再起動すると、登録した名前は消去されます。 また、名前を再登録する場合は、rebindを使います。

 +-----------------+              +-----------------+
 |  +-----------+  |              |  +-----------+  |
 |  |  Client   |  |              |  |  Server   |  |
 |  +-----------+  |              |  +-----------+  |
 |       ↓参照    |              |       ↓登録    |
 |  +-----------+  |              |  +-----------+  |
 |  |  lookup() |  |              |  |  bind()   |  |
 |  +-----------+  |              |  +-----------+  |
 |       │        |              |       ↓        |
 |       │        |              |  +-----------+  |
 |       └------------------------->|rmiregistry|  |
 |                 |              |  +-----------+  |
 +-----------------+              +-----------------+

RMIプログラミング

 RMIのクラスを使うため、java.rmi.*をインポートします。

import java.rmi.*;

リモートインターフェースの定義

 まず、クライアントが参照するリモートインターフェイスを作成します。 インターフェイスは、メソッドの宣言だけで、処理の実体は持ちません。

helloIf.java
import java.rmi.*;

public interface helloIf extends Remote {
  public String helloMsg() throws RemoteException;
}

リモートオブジェクトクラスの作成

 リモートインターフェイスをもとに、サーバ側のリモートオブジェクトを作成します。 リモートオブジェクトは、リモートインターフェイスをimplementsしていますので、同じ引数のメソッドを持つことになります。 RMIのメソッドは、必ず、throws RemoteExceptionを設定する必要があります。
 サンプル(helloObj.java)では、「Hello World!」を返却するメソッド(helloMsg)を作成しています。

helloObj.java
import java.rmi.*;
import java.rmi.server.*;

public class helloObj extends UnicastRemoteObject implements helloIf {
  public helloObj() throws RemoteException {
  }

  public String helloMsg() throws RemoteException {
    return "Hello World!";
  }
}

サーバプログラムの作成

 サーバプログラム(helloServer.java)を作成します。
 RMIでは、セキュリティマネージャを使わない場合は通信できません。
 リモートオブジェクトを作成し、bindメソッドでレジストリサーバに登録します。 レジストリサーバを再起動せずに、何回も登録する場合は、rebindメソッドを使います。

helloServer.java
import java.rmi.*;

public class helloServer {
  public static void main(String args[]) {
    helloObj hello = null;
    try {
      // セキュリティマネージャの設定
      System.setSecurityManager(new RMISecurityManager());

      // リモートオブジェクトの作成
      hello = new helloObj();

      // レジストリサーバに登録(再登録)
      Naming.bind("//localhost/hello", hello);
//    Naming.rebind("//localhost/hello", hello);

    } catch(Exception ex) {
      ex.printStackTrace();
    }
  }
}

クライアントクラスの作成

 クライアントプログラム(helloClient.java)を作成します。
 レジストリサーバから、lookupメソッドでリモートインターフェイスを取得し、「Hello World!」を返却するメソッド(helloMsg)を呼び出します。

helloClient.java
import java.rmi.*;

public class helloClient {
  public static void main(String args[]) {
    helloIf hello = null;
    try {
      // セキュリティマネージャの設定
      System.setSecurityManager(new RMISecurityManager());

      // レジストリサーバの検索
      hello = (helloIf)Naming.lookup("rmi://localhost/hello");

    } catch(Exception ex) {
      ex.printStackTrace();
    }

    try {
      // メッセージの取得
      System.out.println(hello.helloMsg());

    } catch(Exception ex) {
      ex.printStackTrace();
    }
  }
}

Javaソースのコンパイル

 javacで、4つのソースファイルをコンパイルします。

unix# javac *.java
unix# ls *.class

helloObj.class
helloIf.class
helloServer.class
helloClient.class

リモートオブジェクトのコンパイル

 rmicで、リモートオブジェクトをコンパイルします。 コンパイルすると、スタブ(*_Stub.class)とスケルトン(*_Skel.class)が作成されます。
 スタブクラスは、リモートオブジェクトと同じメソッドを持ち、スケルトンに中継します。 また、スケルトンクラスは、ストリームから引数を取り出し、サーバのリモートオブジェクトに中継します。

unix# rmic helloObj
unix# ls helloObj_*

helloObj_Stub.class
helloObj_Skel.class

セキュリティポリシーを記述

 ローカルマシン上でテストする場合は、ポリシーファイル(java.policy)は必要ありません。 リモートホストを使う場合は、RMIによるクラスのダウンロードを参照してください。

RMIレジストリサーバを起動

 RMIレジストリサーバを起動します。UNIX系の場合とWindows系の場合で起動方法が異なります。

・UNIX系の場合
unix# rmiregistry &

・Windows系の場合
win# start rmiregistry

サーバプログラムを起動

 RMIレジストリサーバを起動したら、サーバプログラムを起動します。

unix# java helloServer

クライアントプログラムを起動

 クライアントプログラムを起動し、「Hello World!」と表示されれば、成功です。

unix# java helloClient
Hello World!


Copyright (C)1995-2002 ASH multimedia lab.
mail : info@ash.jp