Поиск…


замечания

RMI требует 3 компонента: клиент, сервер и общий удаленный интерфейс. Общий удаленный интерфейс определяет контракт клиент-сервер, указывая методы, которые должен выполнить сервер. Интерфейс должен быть видимым для сервера, чтобы он мог реализовать методы; интерфейс должен быть виден клиенту, чтобы он знал, какие методы («службы») предоставляют сервер.
Любой объект, реализующий удаленный интерфейс, должен взять на себя роль сервера. Таким образом, отношения клиент-сервер, в которых сервер также может вызывать методы в клиенте, на самом деле являются отношениями сервер-сервер. Это называется обратным вызовом, так как сервер может перезванивать «клиент». Имея это в виду, допустимо использовать клиент назначения для серверов, которые функционируют как таковые.

Общий удаленный интерфейс - это любой интерфейс, расширяющий Remote . Объект, который функционирует как сервер, претерпевает следующие действия:

  1. Реализует общий удаленный интерфейс, явно или неявно, путем расширения UnicastRemoteObject который реализует Remote .
  2. Экспортируется либо неявно, если он расширяет UnicastRemoteObject , либо явно передается в UnicastRemoteObject#exportObject .
  3. Связан в реестре, либо напрямую через Registry либо косвенно через Naming . Это необходимо только для установления первоначальной связи, поскольку дальнейшие заглушки могут быть переданы непосредственно через RMI.

В настройке проекта проекты клиента и сервера полностью не связаны друг с другом, но каждый указывает общий проект в своем пути сборки. Общий проект содержит удаленные интерфейсы.

Client-Server: вызов методов в одном 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 клиента отправляют информацию друг другу через сервер. Один клиент отправляет серверу номер, который передается второму клиенту. Второй клиент уменьшает число и отправляет его первому клиенту через сервер. Первый клиент делает то же самое. Сервер останавливает связь, когда число, возвращаемое им любым из клиентов, меньше 10. Возвращаемое значение от сервера к клиентам (номер, который он преобразовал в строковое представление), затем возвращает процесс.

  1. Сервер входа в систему привязывается к реестру.
  2. Клиент просматривает сервер входа в систему и вызывает метод login в login со своей информацией. Затем:
    • Клиентский сервер хранит информацию о клиенте. Он включает в себя заглушку клиента с методами обратного вызова.
    • Сервер входа в систему создает и возвращает серверную заглушку («соединение» или «сеанс») для хранения клиента. Он включает в себя заглушку сервера с его методами, включая метод logout из logout (в этом примере не используется).
  3. Клиент вызывает passInt сервера с именем клиента-получателя и int .
  4. Сервер вызывает half на клиенте получателя с этим int . Это инициирует обратную связь (обратные вызовы и обратные вызовы) до остановки сервера.

Общие удаленные интерфейсы

Сервер входа в систему:

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 консолях, так как есть 3 JVM. здесь они собраны вместе:

Клиент2 вошел в систему
Клиент1 вошел в систему
Сервер, полученный от Client1: 120
Сервер, полученный от Client2: 60
Сервер, полученный от Client1: 30
Сервер, полученный от Client2: 15
Сервер, полученный от Client1: 7
Клиент1 получил: «7»
Клиент2 получил: «15»
Клиент1 получил: «30»
Клиент2 получил: «60»

Простой пример RMI с внедрением Client и Server

Это простой пример RMI с пятью классами Java и двумя пакетами, сервером и клиентом .

Серверный пакет

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. Выход:
Server : Registry created.
Server : PersonList registered
  • Начните основной метод PersonTest.java. Выход:
Peter Pan
Pippi Langstrumpf


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow