RMI (англ. Remote Method Invocation) - програмний інтерфейс виклику віддалених методів у мові Java.

Опис роботи ред.

Розподілена об'єктна модель, що описує, яким чином здійснюється виклик віддалених методів, що працюють на іншій віртуальній машині Java. При доступі до об'єктів на іншому комп'ютері, можна викликати методи цього об'єкту. Необхідно тільки доставити параметри методу на інший комп'ютер, повідомити об'єкт про необхідність виконання методу, а потім передати назад значення (якщо метод не void). Механізм RMI дає можливість організувати виконання всіх цих операцій.
У термінах RMI об'єкт, який викликає віддалений метод, називається клієнтським об'єктом, а віддалений об'єкт - серверним об'єктом. Комп'ютери виступають у ролі клієнта і сервера тільки для конкретного виклику. Цілком можливо, що при виконанні наступної операції ці комп'ютери поміняються ролями, тобто сервер може сам стати клієнтом при зверненні до об'єкту на іншому комп'ютері.
При виклику методу віддаленого об'єкту, насправді викликається звичайний Java метод, інкапсульований у спеціальному об'єкті-заглушці (stub), який є представником серверного об'єкту. Заглушка знаходиться на клієнтському комп'ютері, а не на сервері. Вона упаковує параметри віддаленого методу у блок байтів. Кожен параметр кодується за допомогою алгоритму, що забезпечує незалежність від апаратного забезпечення. Наприклад, числа завжди передаються в порядку, при якому спочатку передається старший байт (big-endian). При цьому об'єкти піддаються серіалізації. Процес кодування параметрів називається розгортанням параметрів (parameter marshaling). Основна мета розгортання параметрів - перетворення їх у формат, придатний для передачі параметрів від однієї віртуальної машини до іншої.

Метод, який належить заглушці, створює блок, до якого входять такі елементи:

  • ідентифікатор віддаленого об'єкту;
  • опис методу який викликається;
  • розгорнуті параметри.

Потім метод заглушки посилає цю інформацію серверу. Далі об'єкт-одержувач виконує для кожного виклику віддаленого методу наступні дії:

  • згортання параметрів;
  • пошук об'єкту, який викликається;
  • виклик заданого методу;
  • витягування та розгортання значення яке повертається або виключення, згенерованого цим методом;
  • передача пакету, який складається із розгорнутих даних, які повертаються, об'єкту-заглушці на клієнтському комп'ютері.

Клієнтський об'єкт-заглушка згортає повернене значення або виключення, отримане із сервера. Результат згортання стає значенням методу заглушки. Якщо віддалений метод повертає виключення, то об'єкт-заглушка повторить його в середовищі об'єкту-клієнта.

Приклад ред.

Інтерфейс Hello:

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

public interface Hello extends Remote
{
    public String helloWorld () throws RemoteException;
}

Клас HelloImpl:

import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;

public class HelloImpl extends UnicastRemoteObject implements Hello
{
    public HelloImpl() throws RemoteException
    {
        // порожнє, але мусить “кидати” RemoteException
    }
    
    public String helloWorld () throws RemoteException
    {
            return "Hello world!";
    }
}

Клас Server:

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

public class Server 
{
    private static final String SERVER_NAME = "Server";
    private static final String HOST = "localhost";
    
    private String  port;
    public Server(String port)    
    {
        this.port = port;
    }
    
    public void runServer() throws IllegalArgumentException, NotBoundException, RemoteException 
    {
        HelloImpl helloImpl = new HelloImpl();
        Registry registry = LocateRegistry.createRegistry(Integer.parseInt(port, 10));
        String url = "//" + HOST + ":" + port + "/" + SERVER_NAME;
        registry.rebind(SERVER_NAME, helloImpl);
    }
}

Клас Test:

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

public class Test
{
    public static final String SERVER_NAME = "Server";
    // use : server <port> - start server
    // client <host> <port> - start client
    public static void main (String[] args) throws Exception  
    {
        if (args[0].equals("server"))
        {
            Server server = new Server(args[1]);
            server.runServer();
            System.out.println("Server started on port " + args[1]);
        }
        else
        {
            String lookupString = "//" + args[1] + ":" + args[2] + "/" + SERVER_NAME;
            Hello hello = (Hello) Naming.lookup(lookupString);
            System.out.println("RMI object found");
            System.out.println(hello.helloWorld());
        }
    }
}
  1. Компілюємо класи та інтерфейс із командного рядка - javac *.java
  2. Генеруємо заглушку і скелетон(каркас) rmic HelloImpl (отримаємо 2 файла - _stub i _skel)
  3. Запускаємо сервер: java Test server 8888 // будь-який порт > 1023
  4. На іншому комп’ютері запускаємо клієнта: java Test client xxx.xxx.xxx.xxx 8888 // ваш хост

Важливо: Через фаєрвол це працювати не буде.

Див. також ред.

Джерела ред.

  1. http://forum.vingrad.ru/faq/topic-157916.html [Архівовано 28 лютого 2011 у Wayback Machine.] (рос.)
  2. Taylor, Ian J. From P2P to Web Services and Grids - Peers in a Client/Server World. Springer, 2005 (англ.)
  3. http://www.javaworld.com/javaworld/jw-11-2000/jw-1110-smartproxy.html [Архівовано 19 вересня 2013 у Wayback Machine.] (англ.)
  4. The Java RMI tutorial - a good starting point to learn RMI. Also check the Hello World in RMI the Java RMI online training (англ.)
  5. java.rmi (Sun's Java API Reference for the RMI package) (англ.)
  6. Wollrath, Ann; Riggs, Roger; Waldo, Jim (PDF). A Distributed Object Model for the Java System. Retrieved 2009-02-11 (англ.)