サーチ…


備考

RMIには、クライアント、サーバー、および共有リモート・インタフェースの3つのコンポーネントが必要です。共有リモート・インターフェースは、サーバーが実装しなければならないメソッドを指定することによって、クライアント - サーバー契約を定義します。インタフェースは、メソッドを実装できるようにサーバから見える必要があります。サーバが提供するメソッド(「サービス」)を知るために、インタフェースをクライアントに見えるようにする必要があります。
リモートインタフェースを実装するオブジェクトはすべて、サーバーの役割を果たすことを目的としています。したがって、サーバがクライアント内のメソッドも呼び出すことができるクライアント - サーバ関係は、実際にはサーバ - サーバ関係です。これは、サーバーが「クライアント」をコールバックできるので、 コールバックと呼ばれます 。これを念頭に置いて、そのように機能するサーバーに対して指定クライアントを使用することは許容されます

共有リモート・インターフェースは、 Remote拡張する任意のインターフェースです。サーバーとして機能するオブジェクトは、次の処理を実行します。

  1. Remoteを実装するUnicastRemoteObjectを拡張することにより、明示的または暗黙的に共有リモートインタフェースを実装します。
  2. UnicastRemoteObject拡張する場合は暗黙的に、 UnicastRemoteObject#exportObjectに渡すことで明示的にエクスポートされUnicastRemoteObject#exportObject
  3. 直接のいずれかを介して、レジストリにバインドさRegistryまたは間接的に通過Naming 。これは、最初の通信を確立するために必要なのは、さらなるスタブがRMIを介して直接渡されるためです。

プロジェクトセットアップでは、クライアントプロジェクトとサーバープロジェクトは完全に無関係ですが、それぞれがビルドパスに共有プロジェクトを指定しています。共有プロジェクトには、リモートインタフェースが含まれています。

クライアント - サーバ:あるJVMのメソッドを別のJVMから呼び出す

共有リモートインタフェース:

package remote;

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

public interface RemoteServer extends Remote {

    int stringToInt(String string) throws RemoteException;
}

共有リモートインタフェースを実装しているサーバ:

package server;

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

import remote.RemoteServer;

public class Server implements RemoteServer {

    @Override
    public int stringToInt(String string) throws RemoteException {

        System.out.println("Server received: \"" + string + "\"");
        return Integer.parseInt(string);
    }

    public static void main(String[] args) {

        try {
            Registry reg = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
            Server server = new Server();
            UnicastRemoteObject.exportObject(server, Registry.REGISTRY_PORT);
            reg.rebind("ServerName", server);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

サーバー上のメソッドを呼び出すクライアント(リモート):

package client;

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

import remote.RemoteServer;

public class Client {

    static RemoteServer server;

    public static void main(String[] args) {

        try {
            Registry reg = LocateRegistry.getRegistry();
            server = (RemoteServer) reg.lookup("ServerName");
        } catch (RemoteException | NotBoundException e) {
            e.printStackTrace();
        }

        Client client = new Client();
        client.callServer();
    }

    void callServer() {
    
        try {
            int i = server.stringToInt("120");
            System.out.println("Client received: " + i);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

出力:

受信したサーバー: "120"
受け取ったクライアント:120

コールバック: "クライアント"のメソッドを呼び出す

概要

この例では、2つのクライアントがサーバーを介して互いに情報を送信します。 1つのクライアントは、第2のクライアントに中継される番号をサーバに送信する。第2のクライアントは、その番号を半分にして、サーバを介して第1のクライアントに送り返す。最初のクライアントも同様です。サーバは、クライアントから返された数値が10未満のときに通信を停止します。サーバからクライアントへの戻り値(文字列表現に変換された数)は、プロセスをバックトラックします。

  1. ログインサーバーは自身をレジストリにバインドします。
  2. クライアントはログインサーバーを検索し、その情報でloginメソッドを呼び出しlogin 。次に:
    • ログインサーバーはクライアント情報を保管します。これには、コールバックメソッドを持つクライアントのスタブが含まれます。
    • ログインサーバーは、サーバースタブ(「接続」または「セッション」)を作成し、クライアントに保管して戻します。これには、 logoutメソッド(この例では使用されていない)を含むメソッドを含むサーバーのスタブが含まれます。
  3. クライアントは、受信者クライアントの名前とint passIntしてサーバーのpassIntを呼び出します。
  4. サーバーは、そのint受信側クライアントのhalfを呼び出します。これは、サーバーによって停止されるまで、前後の(呼び出しとコールバック)通信を開始します。

共有リモートインタフェース

ログインサーバー:

package callbackRemote;

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

public interface RemoteLogin extends Remote {

    RemoteConnection login(String name, RemoteClient client) throws RemoteException;
}

サーバー:

package callbackRemote;

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

public interface RemoteConnection extends Remote {

    void logout() throws RemoteException;

    String passInt(String name, int i) throws RemoteException;
}

クライアント:

package callbackRemote;

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

public interface RemoteClient extends Remote {

    void half(int i) throws RemoteException;
}

実装

ログインサーバー:

package callbackServer;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.Map;

import callbackRemote.RemoteClient;
import callbackRemote.RemoteConnection;
import callbackRemote.RemoteLogin;

public class LoginServer implements RemoteLogin {

    static Map<String, RemoteClient> clients = new HashMap<>();

    @Override
    public RemoteConnection login(String name, RemoteClient client) {

        Connection connection = new Connection(name, client);
        clients.put(name, client);
        System.out.println(name + " logged in");
        return connection;
    }

    public static void main(String[] args) {

        try {
            Registry reg = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
            LoginServer server = new LoginServer();
            UnicastRemoteObject.exportObject(server, Registry.REGISTRY_PORT);
            reg.rebind("LoginServerName", server);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

サーバー:

package callbackServer;

import java.rmi.NoSuchObjectException;
import java.rmi.RemoteException;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.Unreferenced;

import callbackRemote.RemoteClient;
import callbackRemote.RemoteConnection;

public class Connection implements RemoteConnection, Unreferenced {

    RemoteClient client;
    String name;

    public Connection(String name, RemoteClient client) {

        this.client = client;
        this.name = name;
        try {
            UnicastRemoteObject.exportObject(this, Registry.REGISTRY_PORT);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void unreferenced() {

        try {
            UnicastRemoteObject.unexportObject(this, true);
        } catch (NoSuchObjectException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void logout() {

        try {
            UnicastRemoteObject.unexportObject(this, true);
        } catch (NoSuchObjectException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String passInt(String recipient, int i) {

        System.out.println("Server received from " + name + ":" + i);
        if (i < 10)
            return String.valueOf(i);
        RemoteClient client = LoginServer.clients.get(recipient);
        try {
            client.half(i);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return String.valueOf(i);
    }
}

クライアント:

package callbackClient;

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

import callbackRemote.RemoteClient;
import callbackRemote.RemoteConnection;
import callbackRemote.RemoteLogin;

public class Client implements RemoteClient {

    RemoteConnection connection;
    String name, target;

    Client(String name, String target) {

        this.name = name;
        this.target = target;
    }

    public static void main(String[] args) {

        Client client = new Client(args[0], args[1]);
        try {
            Registry reg = LocateRegistry.getRegistry();
            RemoteLogin login = (RemoteLogin) reg.lookup("LoginServerName");
            UnicastRemoteObject.exportObject(client, Integer.parseInt(args[2]));
            client.connection = login.login(client.name, client);
        } catch (RemoteException | NotBoundException e) {
            e.printStackTrace();
        }

        if ("Client1".equals(client.name)) {
            try {
                client.connection.passInt(client.target, 120);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void half(int i) throws RemoteException {

        String result = connection.passInt(target, i / 2);
        System.out.println(name + " received: \"" + result + "\"");
    }
}

例を実行する:

  1. ログインサーバーを実行します。
  2. 引数Client2 Client1 1097してクライアントを実行します。
  3. 引数Client1 Client2 1098してクライアントを実行します。

3つのJVMがあるため、出力は3つのコンソールに表示されます。ここで彼らは一塊になっています:

Client2がログインしました
Client1がログインしました
クライアント1から受信したサーバー:120
クライアント2から受信したサーバー:60
クライアント1から受信したサーバー:30
クライアント2から受信したサーバー:15
Client1から受信したサーバー:7
受信したClient1:「7」
受信したClient2: "15"
受信したClient1: "30"
受信したClient2: "60"

クライアントとサーバーの実装による単純なRMIの例

これは、5つのJavaクラスと2つのパッケージ( サーバークライアント)を持つ単純なRMIの例です

サーバーパッケージ

PersonListInterface.java

public interface PersonListInterface extends Remote
{
    /**
     * This interface is used by both client and server
     * @return List of Persons
     * @throws RemoteException
     */
    ArrayList<String> getPersonList() throws RemoteException;
}

PersonListImplementation.java

public class PersonListImplementation 
extends UnicastRemoteObject 
implements PersonListInterface
{

    private static final long serialVersionUID = 1L;

    // standard constructor needs to be available
    public PersonListImplementation() throws RemoteException
    {}

    /**
     * Implementation of "PersonListInterface"
     * @throws RemoteException
     */
    @Override
    public ArrayList<String> getPersonList() throws RemoteException
    {
        ArrayList<String> personList = new ArrayList<String>();
        
        personList.add("Peter Pan");
        personList.add("Pippi Langstrumpf");
        // add your name here :)
        
        return personList;
    }
}

Server.java

public class Server {

    /**
     * Register servicer to the known public methods
     */
    private static void createServer() {
        try {
            // Register registry with standard port 1099
            LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
            System.out.println("Server : Registry created.");

            // Register PersonList to registry 
            Naming.rebind("PersonList", new PersonListImplementation());
            System.out.println("Server : PersonList registered");

        } catch (final IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(final String[] args) {
        createServer();
    }
}

クライアントパッケージ

PersonListLocal.java

public class PersonListLocal {
    private static PersonListLocal instance;
    private PersonListInterface personList;

    /**
     * Create a singleton instance
     */
    private PersonListLocal() {
        try {
            // Lookup to the local running server with port 1099
            final Registry registry = LocateRegistry.getRegistry("localhost",
                    Registry.REGISTRY_PORT);

            // Lookup to the registered "PersonList"
            personList = (PersonListInterface) registry.lookup("PersonList");
        } catch (final RemoteException e) {
            e.printStackTrace();
        } catch (final NotBoundException e) {
            e.printStackTrace();
        }
    }

    public static PersonListLocal getInstance() {
        if (instance == null) {
            instance = new PersonListLocal();
        }

        return instance;
    }

    /**
     * Returns the servers PersonList
     */
    public ArrayList<String> getPersonList() {
        if (instance != null) {
            try {
                return personList.getPersonList();
            } catch (final RemoteException e) {
                e.printStackTrace();
            }
        }

        return new ArrayList<>();
    }
       }

PersonTest.java

public class PersonTest
{
    public static void main(String[] args)
    {
        // get (local) PersonList 
        ArrayList<String> personList = PersonListLocal.getInstance().getPersonList();
        
        // print all persons
        for(String person : personList)
        {
            System.out.println(person);
        }
    }
}

アプリケーションのテスト

  • Server.javaのmainメソッドを起動します。出力:
Server : Registry created.
Server : PersonList registered
  • PersonTest.javaのmainメソッドを起動します。出力:
Peter Pan
Pippi Langstrumpf


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow