John Squirrels
レベル 41
San Francisco

Java RMI

ランダム グループに公開済み
やあ!今日は、Java RMI という興味深いトピックについて考えていきます。これはリモート メソッド呼び出しの略です。RMI を使用すると、2 つのプログラムが異なるコンピューター上にある場合でも、相互に通信できるようになります。それはクールだと思いますか?:) そして、それはそれほど難しいことではありません!今日のレッスンでは、RMI インタラクションの要素を分析し、その構成方法を理解します。まず必要なのはクライアントとサーバーです。コンピューター用語を深く掘り下げる必要はありません。RMI に関して言えば、これらは 2 つのプログラムにすぎません。そのうちの 1 つはオブジェクトを含み、もう 1 つはそのオブジェクトのメソッドを呼び出します。別のプログラムに存在するオブジェクトのメソッドを呼び出す - これはまだ行っていないことです。試してみましょう! :) 行き詰まりを避けるために、次のようにしましょう。プログラムをシンプルに保ちます。一般に、サーバーはクライアントから要求されたいくつかの計算を実行します。そしてそれは私たちにも当てはまります。私たちのサーバーは単純な計算プログラムになります。メソッドは 1 つだけです。multiply()。クライアント プログラムから送信された 2 つの数値を乗算し、結果を返します。まず第一に、インターフェースが必要です。

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Calculator extends Remote {

   int multiply(int x, int y) throws RemoteException;
}
なぜインターフェースが必要なのでしょうか? RMI は、過去のレッスンで学習したプロキシの作成に依存しているためです。覚えているかもしれませんが、私たちはクラスではなくインターフェイスを通じてプロキシを操作します。私たちのインターフェースには 2 つの重要な要件があります。
  1. リモート インターフェイスを拡張する必要があります。
  2. そのすべてのメソッドは RemoteException をスローする必要があります (IDE はこれを自動的に実行しません。これを手動で追加する必要があります)。
次に、 Calculatorインターフェイスを実装するサーバー クラスを作成する必要があります。 RMI の実践 - 2ここでも、すべてが非常に単純です。

import java.rmi.RemoteException;

public class RemoteCalculationServer implements Calculator {

   @Override
   public int multiply(int x, int y) throws RemoteException {
       return x*y;
   }

}
ここでは特にコメントすることはありません :) 次に、計算機オブジェクトを構成して実行するサーバー プログラムを作成する必要があります。次のようになります。

import java.rmi.AlreadyBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class ServerMain {

   public static final String UNIQUE_BINDING_NAME = "server.calculator";

   public static void main(String[] args) throws RemoteException, AlreadyBoundException, InterruptedException {

       final RemoteCalculationServer server = new RemoteCalculationServer();

       final Registry registry = LocateRegistry.createRegistry(2732);

       Remote stub = UnicastRemoteObject.exportObject(server, 0);
       registry.bind(UNIQUE_BINDING_NAME, stub);

       Thread.sleep(Integer.MAX_VALUE);

   }
}
これを理解してみましょう:) 最初の行で、文字列変数を宣言します。

public static final String UNIQUE_BINDING_NAME = "server.calculator";
この文字列は、リモート オブジェクトの一意の名前です。クライアント プログラムはこの名前を使用してサーバーを検索します。これについては後で説明します。次に、計算機オブジェクトを作成します。

final RemoteCalculationServer server = new RemoteCalculationServer();
ここではすべてが明らかです。次に来るのはさらに興味深いものです。

final Registry registry = LocateRegistry.createRegistry(2732);
このレジストリ オブジェクトは、リモート オブジェクトのレジストリです。これらは、他のプログラムがリモートでアクセスできるオブジェクトです :) 数値 2732 をLocateRegistry.createRegistry()メソッドに渡しました。これはポート番号です。他のプログラムがオブジェクト レジストリを見つけるために使用する一意の番号です (これも以下で説明します)。次に進みます...次の行で何が起こるかを見てみましょう。

Remote stub = UnicastRemoteObject.exportObject(server, 0);
この行にスタブを作成します。スタブはリモート呼び出し全体をカプセル化します。これは RMI の最も重要な要素であると考えることができます。それは何をするためのものか?
  1. 何らかのメソッドのリモート呼び出しに関するすべての情報を受け取ります。
  2. メソッドにパラメータがある場合、スタブはパラメータを逆シリアル化します。この点に注目してください!リモートで呼び出されるメソッドに渡す引数はシリアル化可能である必要があります (結局のところ、引数はネットワーク経由で送信されます)。これは私たちにとって問題ではありません。私たちは単に数字を送信しているだけです。ただし、オブジェクトを送信する場合は、この要件を忘れないでください。
  3. その後、スタブは目的のメソッドを呼び出します。
計算機サーバー オブジェクトをUnicastRemoteObject.exportObject()メソッドに渡します。これにより、そのメソッドをリモートから呼び出すことができるようになります。やるべきことは 1 つだけ残っています。

registry.bind(UNIQUE_BINDING_NAME, stub);
最初に作成した名前でリモート オブジェクト レジストリにスタブを「登録」します。これでクライアントはそれを見つけることができるようになります。おそらく、最後にプログラムのメインスレッドをスリープ状態にしていることに気づいたかもしれません。

Thread.sleep(Integer.MAX_VALUE);
サーバーを長時間稼働させる必要があるだけです。IDE では、2 つのmain()メソッドを同時に起動します。1 つ目はサーバーの main() メソッド (すでに作成したServerMainクラス内)、2 つ目はクライアントの main() メソッド ( ClientMainクラス内)以下に書きます)。クライアントの起動中にサーバー プログラムが終了しないことが重要なので、クライアントを長時間スリープ状態にします。いずれにしても、実行は継続されます:) これで、サーバーのmain()メソッドを実行できるようになりました。実行して、クライアント プログラムが何らかのメソッドを呼び出すまで待ち​​ます :) 次に、クライアント プログラムを作成しましょう。乗算のために数値をサーバーに送信します。

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class ClientMain {

   public static final String UNIQUE_BINDING_NAME = "server.calculator";

   public static void main(String[] args) throws RemoteException, NotBoundException {

       final Registry registry = LocateRegistry.getRegistry(2732);

       Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);

       int multiplyResult = calculator.multiply(20, 30);

       System.out.println(multiplyResult);
   }
}
見た目はシンプルです。しかし、ここで何が起こっているのでしょうか?まず、クライアントは、リモートで呼び出すメソッドのオブジェクトの一意の名前を知っている必要があります。したがって、クライアント プログラムでは、public static Final String UNIQUE_BINDING_NAME = "server.calculator";を作成しました。変数。 次に、main()メソッドで、リモート オブジェクトのレジスタにアクセスします。これを行うには、LocateRegistry.getRegistry()メソッドを呼び出し、ServerMain プログラムでレジストリの作成に使用されるポート番号 (ポート 2732、この番号は単なる例です。別の番号を使用してみても構いません) を渡す必要があります。

final Registry registry = LocateRegistry.getRegistry(2732);
あとは、レジストリから目的のオブジェクトを取得するだけです。固有の名前がわかっているので、これは簡単です。

Calculator calculator = (Calculator) registry.lookup(UNIQUE_BINDING_NAME);
型キャストに注意してください。受信したオブジェクトをRemoteCalculationServerクラスではなくCalculatorインターフェイスにキャストします。レッスンの冒頭で述べたように、RMI はプロキシに依存しているため、リモート呼び出しはインターフェイスのメソッドに対してのみ使用でき、クラスのメソッドに対しては使用できません。最後に、オブジェクトの multiply()メソッドをリモートで呼び出し、結果をコンソールに出力します。

int multiplyResult = calculator.multiply(20, 30);
System.out.println(multiplyResult);
ServerMainクラスのmain()メソッドはすでに長期間実行されています。次に、クライアント プログラム ( ClientMain ) でmain()メソッドを実行します。コンソール出力:

600
それでおしまい!私たちのプログラム (実際には 2 つのプログラムです!) は、やるべきことを実行しました :) 時間と希望があれば、これに少しスパイスを加えることができます。たとえば、電卓で標準の四則演算をサポートし、数値をプリミティブ型としてではなくCalculationInstance(int x, int y)オブジェクトとして渡します。次のレッスンでお会いしましょう!:)
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION