Как написать rmi клиент

Время на прочтение
5 мин

Количество просмотров 79K

Случилось так, что поставленная задача требовала применения удалённого вызова методов. Порывшись на Хабре, ничего не нашел по данному вопросу (хотелось что-нибудь почитать в качестве первого знакомства, перед чтением документации). Изучив спецификации на java.sun.com спешу поделиться с вами своей первой статьей. :)

«Что такое RMI?»

Remote method Invocation — механизм, который позволяет вызывать метод удалённого объекта. Согласно ему, все операции по подготовке и передаче данных инкапсулируются в вызываемом методе клиентского объекта-заглушки (stub). Сам же вызов метода ничем не отличается от вызова метода обычного локального объекта, за небольшим исключением:

  • все параметры передаются по значению (т.е. копии объектов, а не ссылки на них, как это обычно происходит) — исправил ниже. Спасибо KonstantinSolomatov
  • локальные объекты передаются по значению (копии)
  • при передаче удалённого (Remote) объекта, если он экспортирован, передаётся stub этого объекта
  • передаваемые объекты должны быть Serializable
  • кроме всех прочих исключительных ситуаций, при вызове удалённого метода может возбуждаться исключение RemoteException (ошибки маршализации/демаршализации, передачи данных и другие возможные ошибки протокола)

Так же нужно отметить, что при вызове метода мы работаем с удалённым интерфейсом, а не с удалённым классом.

«Зачем это нужно?»

Задача RMI — организация клиент-серверного взаимодействия. Это значит, что вам не придётся беспокоится о передаче и предварительной обработке данных (протокол и т.д.). Удобно? Да. Но не во всех случаях. Если в вашей клиент-серверной среде подразумевается работа программ, написанных не только на java, от RMI толку мало (хотя при большом желании можно попытаться «выкрутиться» при помощи JNI).

«Давайте уже что-нибудь напишем!»

Давайте. Рассмотрим на примере распределённых вычислений. Задача у нас такая: мы будем искать простые числа самым простым способом, перебором. Распределённо же будем проверять числа подбором делителей от 2 до sqrt(n), где n — число, которое проверяем. («Распределённые вычисления» — громкое название для такого примера. Но ведь вычисляем? Да! Распределённо? Распределённо!)

Решать задачу будем так: есть сервер, который будет «скармливать» числа на проверку «зарегистрировавшимся» клиентам, посему взаимодействовать мы будем в обоих направлениях (клиент->сервер — регистрация, сервер->клиент — число на проверку), для этого опишем 2 интерфейса:

  1. public interface ClientRegister extends Remote {
  2.   public void register (PrimeChecker checker) throws RemoteException;
  3. }
  4.  
  5. public interface PrimeChecker extends Remote {
  6.   public boolean check (BigDecimal number) throws RemoteException;
  7. }

* This source code was highlighted with Source Code Highlighter.

Интерфейс ClientRegister ипользуется клиентом для регистрации себя на сервере в роли PrimeChecker`a. Сервер использует PrimeChecker для передачи клиенту числа на проверку.

Как вы уже заметили, удалённый интерфейс должен расширять, прямо или косвенно, интерфейс Remote. Так же среди прочих исключений определим RemoteException (о нём мы говорили выше).

Приступим к реализации сервера (полный код):

  1. public class PrimeNumbersSearchServer implements ClientRegister {
  2.  
  3.   ...
  4.  
  5.   public static void main(String[] args) {
  6.     PrimeNumbersSearchServer server = new PrimeNumbersSearchServer();
  7.  
  8.     try {
  9.       ClientRegister stub = (ClientRegister)UnicastRemoteObject.exportObject(server, 0);
  10.  
  11.       Registry registry = LocateRegistry.createRegistry(12345);
  12.       registry.bind("ClientRegister", stub);
  13.  
  14.       server.startSearch();
  15.     } catch (Exception e) {
  16.       System.out.println ("Error occured: " + e.getMessage());
  17.       System.exit (1);
  18.     }
  19.   }
  20. }

* This source code was highlighted with Source Code Highlighter.

Разберём инициализацию:

  1. ClientRegister stub = (ClientRegister)UnicastRemoteObject.exportObject(server, 0);

* This source code was highlighted with Source Code Highlighter.

Экспортируем удалённый объект и получаем stub, посредством которого клиент будет вызывать методы нашего объекта. Второй параметр exportObject — порт, который будет использоваться для соеденения с удалённым объектом, 0 — выбор любого свободного порта. stub нужно передать клиенту. Тут возможны совершенно разные варианты. Можно даже передать stub клиенту на дискете 3.5» :) Мы воспользуемся RMI-регистратором. Его можно как создать внутри нашей vm, так и использовать «внешний», представляемый утилитой rmiregistry. Я использовал первый вариант:

  1. Registry registry = LocateRegistry.createRegistry(12345);
  2. registry.bind("ClientRegister", stub);

* This source code was highlighted with Source Code Highlighter.

Создаём регистратор и связываем наш stub с именем ClientRegister. Регистратор будет принимать соеденения на 12345 порту.

Теперь клиент (полный код):

  1. public class PrimeNumbersSearchClient implements PrimeChecker {
  2.  
  3.   ...
  4.  
  5.   public static void main(String[] args) {
  6.     PrimeNumbersSearchClient client = new PrimeNumbersSearchClient();
  7.  
  8.     try {
  9.       Registry registry = LocateRegistry.getRegistry(null, 12345);
  10.       ClientRegister server = (ClientRegister)registry.lookup("ClientRegister");
  11.  
  12.       PrimeChecker stub = (PrimeChecker)UnicastRemoteObject.exportObject(client, 0);
  13.       server.register(stub);
  14.  
  15.     } catch (Exception e) {
  16.       System.out.println ("Error occured: " + e.getMessage());
  17.       System.exit (1);
  18.     }
  19.   }
  20. }

* This source code was highlighted with Source Code Highlighter.

Клиенту нужно получить серверный stub, чтобы зарегистрироваться.

  1. Registry registry = LocateRegistry.getRegistry(null, 12345);
  2. ClientRegister server = (ClientRegister)registry.lookup("ClientRegister");

* This source code was highlighted with Source Code Highlighter.

Находим удалённый регистратор и запрашиваем у него stub связанный с именем «ClientRegister». Первый параметр LocateRegistry.getRegistry(null, 12345) — хост (null — localhost), второй — порт.

Далее экспортируем клиентский удалённый объект и передадим серверу stub (уже клиентский) — зарегистрируемся. Сервер добавит клиента в очередь доступных checker’ов и начнёт передавать ему числа для проверки. После проверки, если она завершилась без ошибок, клиент снова попадает в очередь и т.д.

UPD: перенёс в Java

Java RMI – Введение

RMI обозначает дистанционный вызов метода . Это механизм, который позволяет объекту, находящемуся в одной системе (JVM), получать доступ / вызывать объект, запущенный в другой JVM.

RMI используется для создания распределенных приложений; он обеспечивает удаленную связь между Java-программами. Это предусмотрено в пакете java.rmi .

Архитектура приложения RMI

В приложении RMI мы пишем две программы: серверную (на сервере) и клиентскую (на клиенте).

  • Внутри серверной программы создается удаленный объект, и ссылка на этот объект становится доступной для клиента (с использованием реестра).

  • Клиентская программа запрашивает удаленные объекты на сервере и пытается вызвать его методы.

Внутри серверной программы создается удаленный объект, и ссылка на этот объект становится доступной для клиента (с использованием реестра).

Клиентская программа запрашивает удаленные объекты на сервере и пытается вызвать его методы.

Следующая диаграмма показывает архитектуру приложения RMI.

Архитектура RMI

Давайте теперь обсудим компоненты этой архитектуры.

  • Транспортный уровень – этот уровень связывает клиента и сервер. Он управляет существующим соединением, а также устанавливает новые соединения.

  • Заглушка – заглушка – это представление (прокси) удаленного объекта на клиенте. Он находится в клиентской системе; он действует как шлюз для клиентской программы.

  • Скелет – это объект, который находится на стороне сервера. заглушка связывается с этим скелетом для передачи запроса удаленному объекту.

  • RRL (Remote Reference Layer) – это уровень, который управляет ссылками, сделанными клиентом на удаленный объект.

Транспортный уровень – этот уровень связывает клиента и сервер. Он управляет существующим соединением, а также устанавливает новые соединения.

Заглушка – заглушка – это представление (прокси) удаленного объекта на клиенте. Он находится в клиентской системе; он действует как шлюз для клиентской программы.

Скелет – это объект, который находится на стороне сервера. заглушка связывается с этим скелетом для передачи запроса удаленному объекту.

RRL (Remote Reference Layer) – это уровень, который управляет ссылками, сделанными клиентом на удаленный объект.

Работа приложения RMI

Следующие пункты суммируют, как работает приложение RMI –

  • Когда клиент выполняет вызов к удаленному объекту, он принимается заглушкой, которая в конечном итоге передает этот запрос в RRL.

  • Когда RRL на стороне клиента получает запрос, он вызывает метод invoke () объекта remoteRef . Он передает запрос в RRL на стороне сервера.

  • RRL на стороне сервера передает запрос в Skeleton (прокси-сервер на сервере), который, наконец, вызывает требуемый объект на сервере.

  • Результат передается обратно клиенту.

Когда клиент выполняет вызов к удаленному объекту, он принимается заглушкой, которая в конечном итоге передает этот запрос в RRL.

Когда RRL на стороне клиента получает запрос, он вызывает метод invoke () объекта remoteRef . Он передает запрос в RRL на стороне сервера.

RRL на стороне сервера передает запрос в Skeleton (прокси-сервер на сервере), который, наконец, вызывает требуемый объект на сервере.

Результат передается обратно клиенту.

Маршаллинг и демаршаллинг

Всякий раз, когда клиент вызывает метод, который принимает параметры на удаленном объекте, параметры объединяются в сообщение перед отправкой по сети. Эти параметры могут быть примитивного типа или объектов. В случае примитивного типа параметры объединяются и к нему прикрепляется заголовок. Если параметры являются объектами, они сериализуются. Этот процесс известен как сортировка .

На стороне сервера упакованные параметры разделяются, а затем вызывается требуемый метод. Этот процесс известен как демаршаллинг .

Реестр RMI

Реестр RMI – это пространство имен, в котором размещены все объекты сервера. Каждый раз, когда сервер создает объект, он регистрирует этот объект в RMIregistry (используя методы bind () или reBind () ). Они зарегистрированы с использованием уникального имени, известного как имя привязки .

Чтобы вызвать удаленный объект, клиенту нужна ссылка на этот объект. В это время клиент выбирает объект из реестра, используя его имя привязки (используя метод lookup () ).

Следующая иллюстрация объясняет весь процесс –

реестр

Цели РМИ

Ниже приведены цели RMI –

  • Чтобы минимизировать сложность приложения.
  • Чтобы сохранить безопасность типов.
  • Распределенная сборка мусора.
  • Минимизируйте разницу между работой с локальными и удаленными объектами.

Приложение Java RMI

Чтобы написать Java-приложение RMI, вам необходимо выполнить следующие шаги:

  • Определите удаленный интерфейс
  • Разработать класс реализации (удаленный объект)
  • Разработать серверную программу
  • Разработать клиентскую программу
  • Скомпилируйте приложение
  • Выполнить заявку

Определение удаленного интерфейса

Удаленный интерфейс предоставляет описание всех методов конкретного удаленного объекта. Клиент связывается с этим удаленным интерфейсом.

Чтобы создать удаленный интерфейс –

  • Создайте интерфейс, который расширяет предопределенный интерфейс Remote, который принадлежит пакету.

  • Объявите все бизнес-методы, которые могут быть вызваны клиентом в этом интерфейсе.

  • Поскольку существует вероятность возникновения проблем с сетью во время удаленных вызовов, может возникнуть исключение с именем RemoteException ; брось это.

Создайте интерфейс, который расширяет предопределенный интерфейс Remote, который принадлежит пакету.

Объявите все бизнес-методы, которые могут быть вызваны клиентом в этом интерфейсе.

Поскольку существует вероятность возникновения проблем с сетью во время удаленных вызовов, может возникнуть исключение с именем RemoteException ; брось это.

Ниже приведен пример удаленного интерфейса. Здесь мы определили интерфейс с именем Hello, и у него есть метод с именем printMsg () .

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

// Creating Remote interface for our application 
public interface Hello extends Remote {  
   void printMsg() throws RemoteException;  
} 

Разработка класса реализации (удаленный объект)

Нам нужно реализовать удаленный интерфейс, созданный на предыдущем шаге. (Мы можем написать класс реализации отдельно или мы можем напрямую заставить серверную программу реализовать этот интерфейс.)

Разработать класс реализации –

  • Реализуйте интерфейс, созданный на предыдущем шаге.
  • Обеспечить реализацию всех абстрактных методов удаленного интерфейса.

Ниже приведен класс реализации. Здесь мы создали класс с именем ImplExample и реализовали интерфейс Hello, созданный на предыдущем шаге, и предоставили тело для этого метода, который печатает сообщение.

// Implementing the remote interface 
public class ImplExample implements Hello {  
   
   // Implementing the interface method 
   public void printMsg() {  
      System.out.println("This is an example RMI program");  
   }  
} 

Разработка серверной программы

Программа сервера RMI должна реализовывать удаленный интерфейс или расширять класс реализации. Здесь мы должны создать удаленный объект и связать его с RMIregistry .

Разработать серверную программу –

  • Создайте клиентский класс, из которого вы хотите вызвать удаленный объект.

  • Создайте удаленный объект , создав экземпляр класса реализации, как показано ниже.

  • Экспортируйте удаленный объект, используя метод exportObject () класса с именем UnicastRemoteObject, который принадлежит пакету java.rmi.server .

  • Получить реестр RMI с помощью метода getRegistry () класса LocateRegistry, который принадлежит пакету java.rmi.registry .

  • Свяжите удаленный объект, созданный с реестром, используя метод bind () класса Registry . В этот метод передайте строку, представляющую имя привязки и экспортируемый объект, в качестве параметров.

Создайте клиентский класс, из которого вы хотите вызвать удаленный объект.

Создайте удаленный объект , создав экземпляр класса реализации, как показано ниже.

Экспортируйте удаленный объект, используя метод exportObject () класса с именем UnicastRemoteObject, который принадлежит пакету java.rmi.server .

Получить реестр RMI с помощью метода getRegistry () класса LocateRegistry, который принадлежит пакету java.rmi.registry .

Свяжите удаленный объект, созданный с реестром, используя метод bind () класса Registry . В этот метод передайте строку, представляющую имя привязки и экспортируемый объект, в качестве параметров.

Ниже приведен пример программы RMI-сервера.

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

public class Server extends ImplExample { 
   public Server() {} 
   public static void main(String args[]) { 
      try { 
         // Instantiating the implementation class 
         ImplExample obj = new ImplExample(); 
    
         // Exporting the object of implementation class  
         // (here we are exporting the remote object to the stub) 
         Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0);  
         
         // Binding the remote object (stub) in the registry 
         Registry registry = LocateRegistry.getRegistry(); 
         
         registry.bind("Hello", stub);  
         System.err.println("Server ready"); 
      } catch (Exception e) { 
         System.err.println("Server exception: " + e.toString()); 
         e.printStackTrace(); 
      } 
   } 
} 

Разработка клиентской программы

Напишите в нем клиентскую программу, извлеките удаленный объект и вызовите требуемый метод, используя этот объект.

Разработать клиентскую программу –

  • Создайте клиентский класс, из которого вы собираетесь вызывать удаленный объект.

  • Получить реестр RMI с помощью метода getRegistry () класса LocateRegistry, который принадлежит пакету java.rmi.registry .

  • Получите объект из реестра, используя метод lookup () класса Registry, который принадлежит пакету java.rmi.registry .

    В этот метод необходимо передать строковое значение, представляющее имя привязки, в качестве параметра. Это вернет вам удаленный объект.

  • Функция lookup () возвращает объект типа remote, затем преобразует его в тип Hello.

  • Наконец, вызовите требуемый метод, используя полученный удаленный объект.

Создайте клиентский класс, из которого вы собираетесь вызывать удаленный объект.

Получить реестр RMI с помощью метода getRegistry () класса LocateRegistry, который принадлежит пакету java.rmi.registry .

Получите объект из реестра, используя метод lookup () класса Registry, который принадлежит пакету java.rmi.registry .

В этот метод необходимо передать строковое значение, представляющее имя привязки, в качестве параметра. Это вернет вам удаленный объект.

Функция lookup () возвращает объект типа remote, затем преобразует его в тип Hello.

Наконец, вызовите требуемый метод, используя полученный удаленный объект.

Ниже приведен пример клиентской программы RMI.

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

public class Client {  
   private Client() {}  
   public static void main(String[] args) {  
      try {  
         // Getting the registry 
         Registry registry = LocateRegistry.getRegistry(null); 
    
         // Looking up the registry for the remote object 
         Hello stub = (Hello) registry.lookup("Hello"); 
    
         // Calling the remote method using the obtained object 
         stub.printMsg(); 
         
         // System.out.println("Remote method invoked"); 
      } catch (Exception e) {
         System.err.println("Client exception: " + e.toString()); 
         e.printStackTrace(); 
      } 
   } 
}

Компиляция приложения

Чтобы скомпилировать приложение –

  • Скомпилируйте интерфейс Remote.
  • Скомпилируйте класс реализации.
  • Скомпилируйте серверную программу.
  • Скомпилируйте клиентскую программу.

Или же,

Откройте папку, в которой вы сохранили все программы, и скомпилируйте все файлы Java, как показано ниже.

Javac *.java

Хранимые Программы

Выполнение заявки

Шаг 1 – Запустите реестр rmi, используя следующую команду.

start rmiregistry

Начать выполнение

Это запустит реестр rmi в отдельном окне, как показано ниже.

Отдельное окно

Шаг 2 – Запустите файл класса сервера, как показано ниже.

Java Server

Запустить сервер

Шаг 3 – Запустите файл класса клиента, как показано ниже.

java Client 

Запустить клиент

Проверка – как только вы запустите клиент, вы увидите следующий вывод на сервере.

Выход

Java RMI – приложение с графическим интерфейсом

В предыдущей главе мы создали пример приложения RMI. В этой главе мы объясним, как создать приложение RMI, где клиент вызывает метод, который отображает окно графического интерфейса пользователя (JavaFX).

Определение удаленного интерфейса

Здесь мы определяем удаленный интерфейс с именем Hello, в котором есть метод animation () .

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

// Creating Remote interface for our application 
public interface Hello extends Remote { 
   void animation() throws RemoteException; 
}

Разработка класса реализации

В классе реализации (удаленный объект) этого приложения мы пытаемся создать окно, отображающее содержимое графического интерфейса, используя JavaFX.

import javafx.animation.RotateTransition;  
import javafx.application.Application;  
import javafx.event.EventHandler;   

import javafx.scene.Group;  
import javafx.scene.PerspectiveCamera;  
import javafx.scene.Scene;  
import javafx.scene.control.TextField;  
import javafx.scene.input.KeyEvent;  
import javafx.scene.paint.Color;  
import javafx.scene.paint.PhongMaterial; 
  
import javafx.scene.shape.Box;  
import javafx.scene.text.Font;  
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;   
import javafx.scene.transform.Rotate;  

import javafx.stage.Stage;  
import javafx.util.Duration;  

// Implementing the remote interface 
public class FxSample extends Application implements Hello {  
   @Override  
   public void start(Stage stage) { 
      // Drawing a Box  
      Box box = new Box();  

      // Setting the properties of the Box  
      box.setWidth(150.0);  
      box.setHeight(150.0);    
      box.setDepth(100.0);  

      // Setting the position of the box  
      box.setTranslateX(350);   
      box.setTranslateY(150);  
      box.setTranslateZ(50);  

      // Setting the text  
      Text text = new Text(
         "Type any letter to rotate the box, and click on the box to stop the rotation");

      // Setting the font of the text  
      text.setFont(Font.font(null, FontWeight.BOLD, 15));      

      // Setting the color of the text  
      text.setFill(Color.CRIMSON);  

      // Setting the position of the text  
      text.setX(20);  
      text.setY(50); 

      // Setting the material of the box  
      PhongMaterial material = new PhongMaterial();   
      material.setDiffuseColor(Color.DARKSLATEBLUE);   

      // Setting the diffuse color material to box  
      box.setMaterial(material);        

      // Setting the rotation animation to the box     
      RotateTransition rotateTransition = new RotateTransition();  

      // Setting the duration for the transition  
      rotateTransition.setDuration(Duration.millis(1000));  

      // Setting the node for the transition  
      rotateTransition.setNode(box);        

      // Setting the axis of the rotation  
      rotateTransition.setAxis(Rotate.Y_AXIS);  

      // Setting the angle of the rotation 
      rotateTransition.setByAngle(360);  

      // Setting the cycle count for the transition  
      rotateTransition.setCycleCount(50);  

      // Setting auto reverse value to false  
      rotateTransition.setAutoReverse(false);   

      // Creating a text filed  
      TextField textField = new TextField();    

      // Setting the position of the text field  
      textField.setLayoutX(50);  
      textField.setLayoutY(100);  

      // Handling the key typed event  
      EventHandler<KeyEvent> eventHandlerTextField = new EventHandler<KeyEvent>() {  
         @Override  
         public void handle(KeyEvent event) {  
            // Playing the animation  
            rotateTransition.play();  
         }            
      };               
      
      // Adding an event handler to the text feld  
      textField.addEventHandler(KeyEvent.KEY_TYPED, eventHandlerTextField);  

      // Handling the mouse clicked event(on box)  
      EventHandler<javafx.scene.input.MouseEvent> eventHandlerBox =  
         new EventHandler<javafx.scene.input.MouseEvent>() {  
         @Override  
         public void handle(javafx.scene.input.MouseEvent e) {  
            rotateTransition.stop();   
         }  
      };  
      
      // Adding the event handler to the box   
      box.addEventHandler(javafx.scene.input.MouseEvent.MOUSE_CLICKED, eventHandlerBox); 

      // Creating a Group object 
      Group root = new Group(box, textField, text);  

      // Creating a scene object  
      Scene scene = new Scene(root, 600, 300);       

      // Setting camera  
      PerspectiveCamera camera = new PerspectiveCamera(false);  
      camera.setTranslateX(0);  
      camera.setTranslateY(0);  
      camera.setTranslateZ(0);  
      scene.setCamera(camera);   

      // Setting title to the Stage
      stage.setTitle("Event Handlers Example");  

      // Adding scene to the stage  
      stage.setScene(scene);  

      // Displaying the contents of the stage  
      stage.show();  
   }  

   // Implementing the interface method 
   public void animation() {  
      launch();  
   }  
}

Серверная программа

Программа сервера RMI должна реализовывать удаленный интерфейс или расширять класс реализации. Здесь мы должны создать удаленный объект и связать его с RMIregistry .

Ниже приводится серверная программа этого приложения. Здесь мы расширим созданный выше класс, создадим удаленный объект и зарегистрируем его в реестре RMI с именем привязки hello .

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

public class Server extends FxSample { 
   public Server() {} 
   public static void main(String args[]) { 
      try { 
         // Instantiating the implementation class 
         FxSample obj = new FxSample();
      
         // Exporting the object of implementation class  
         // (here we are exporting the remote object to the stub) 
         Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0);  
      
         // Binding the remote object (stub) in the registry 
         Registry registry = LocateRegistry.getRegistry(); 
         
         registry.bind("Hello", stub);  
         System.err.println("Server ready"); 
      } catch (Exception e) { 
         System.err.println("Server exception: " + e.toString()); 
         e.printStackTrace(); 
      } 
   } 
}

Клиентская программа

Ниже приведена клиентская программа этого приложения. Здесь мы выбираем удаленный объект и вызываем его метод с именем animation () .

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

public class Client { 
   private Client() {} 
   public static void main(String[] args) {  
      try { 
         // Getting the registry 
         Registry registry = LocateRegistry.getRegistry(null); 
    
         // Looking up the registry for the remote object 
         Hello stub = (Hello) registry.lookup("Hello"); 
         
         // Calling the remote method using the obtained object 
         stub.animation(); 
         
         System.out.println("Remote method invoked"); 
      } catch (Exception e) {
         System.err.println("Client exception: " + e.toString()); 
         e.printStackTrace(); 
      } 
   } 
}

Шаги для запуска примера

Ниже приведены шаги для запуска нашего примера RMI.

Шаг 1 – Откройте папку, в которой вы сохранили все программы, и скомпилируйте все файлы Java, как показано ниже.

Javac *.java

Хранимые Программы

Шаг 2 – Запустите реестр rmi, используя следующую команду.

start rmiregistry

Начать выполнение

Это запустит реестр rmi в отдельном окне, как показано ниже.

Отдельное окно

Шаг 3 – Запустите файл класса сервера, как показано ниже.

Java Server

Запустить сервер

Шаг 4 – Запустите файл класса клиента, как показано ниже.

java Client

Клиентский класс

Проверка – как только вы запустите клиент, вы увидите следующий вывод на сервере.

Обработчик события

Java RMI – Приложение базы данных

В предыдущей главе мы создали образец приложения RMI, в котором клиент вызывает метод, который отображает окно графического интерфейса пользователя (JavaFX).

В этой главе мы рассмотрим пример того, как клиентская программа может извлекать записи из таблицы в базе данных MySQL, находящейся на сервере.

Предположим, у нас есть таблица с именем student_data в деталях базы данных, как показано ниже.

+----+--------+--------+------------+---------------------+ 
| ID | NAME   | BRANCH | PERCENTAGE | EMAIL               | 
+----+--------+--------+------------+---------------------+ 
|  1 | Ram    | IT     |         85 | ram123@gmail.com    | 
|  2 | Rahim  | EEE    |         95 | rahim123@gmail.com  | 
|  3 | Robert | ECE    |         90 | robert123@gmail.com | 
+----+--------+--------+------------+---------------------+ 

Предположим, что имя пользователя myuser, а пароль – пароль .

Создание студенческого класса

Создайте класс Student с методами установки и получения, как показано ниже.

public class Student implements java.io.Serializable {   
   private int id, percent;   
   private String name, branch, email;    
  
   public int getId() { 
      return id; 
   } 
   public String getName() { 
      return name; 
   } 
   public String getBranch() { 
      return branch; 
   } 
   public int getPercent() { 
      return percent; 
   } 
   public String getEmail() { 
      return email; 
   } 
   public void setID(int id) { 
      this.id = id; 
   } 
   public void setName(String name) { 
      this.name = name; 
   } 
   public void setBranch(String branch) { 
      this.branch = branch; 
   } 
   public void setPercent(int percent) { 
      this.percent = percent; 
   } 
   public void setEmail(String email) { 
      this.email = email; 
   } 
}

Определение удаленного интерфейса

Определите удаленный интерфейс. Здесь мы определяем удаленный интерфейс с именем Hello, в котором есть метод getStudents () . Этот метод возвращает список, который содержит объект класса Student .

import java.rmi.Remote; 
import java.rmi.RemoteException; 
import java.util.*;

// Creating Remote interface for our application 
public interface Hello extends Remote {  
   public List<Student> getStudents() throws Exception;  
}

Разработка класса реализации

Создайте класс и реализуйте созданный выше интерфейс.

Здесь мы реализуем метод getStudents () интерфейса Remote . Когда вы вызываете этот метод, он получает записи таблицы с именем student_data . Устанавливает эти значения для класса Student с использованием его методов установки, добавляет его в объект списка и возвращает этот список.

import java.sql.*; 
import java.util.*;  

// Implementing the remote interface 
public class ImplExample implements Hello {  
   
   // Implementing the interface method 
   public List<Student> getStudents() throws Exception {  
      List<Student> list = new ArrayList<Student>();   
    
      // JDBC driver name and database URL 
      String JDBC_DRIVER = "com.mysql.jdbc.Driver";   
      String DB_URL = "jdbc:mysql://localhost:3306/details";  
      
      // Database credentials 
      String USER = "myuser"; 
      String PASS = "password";  
      
      Connection conn = null; 
      Statement stmt = null;  
      
      //Register JDBC driver 
      Class.forName("com.mysql.jdbc.Driver");   
      
      //Open a connection
      System.out.println("Connecting to a selected database..."); 
      conn = DriverManager.getConnection(DB_URL, USER, PASS); 
      System.out.println("Connected database successfully...");  
      
      //Execute a query 
      System.out.println("Creating statement..."); 
      
      stmt = conn.createStatement();  
      String sql = "SELECT * FROM student_data"; 
      ResultSet rs = stmt.executeQuery(sql);  
      
      //Extract data from result set 
      while(rs.next()) { 
         // Retrieve by column name 
         int id  = rs.getInt("id"); 
         
         String name = rs.getString("name"); 
         String branch = rs.getString("branch"); 
         
         int percent = rs.getInt("percentage"); 
         String email = rs.getString("email");  
         
         // Setting the values 
         Student student = new Student(); 
         student.setID(id); 
         student.setName(name); 
         student.setBranch(branch); 
         student.setPercent(percent); 
         student.setEmail(email); 
         list.add(student); 
      } 
      rs.close(); 
      return list;     
   }  
}

Серверная программа

Программа сервера RMI должна реализовывать удаленный интерфейс или расширять класс реализации. Здесь мы должны создать удаленный объект и связать его с реестром RMI .

Ниже приводится серверная программа этого приложения. Здесь мы расширим созданный выше класс, создадим удаленный объект и зарегистрируем его в реестре RMI с именем привязки hello .

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

public class Server extends ImplExample { 
   public Server() {} 
   public static void main(String args[]) { 
      try { 
         // Instantiating the implementation class 
         ImplExample obj = new ImplExample(); 
    
         // Exporting the object of implementation class (
            here we are exporting the remote object to the stub) 
         Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0);  
         
         // Binding the remote object (stub) in the registry 
         Registry registry = LocateRegistry.getRegistry(); 
         
         registry.bind("Hello", stub);  
         System.err.println("Server ready"); 
      } catch (Exception e) { 
         System.err.println("Server exception: " + e.toString()); 
         e.printStackTrace(); 
      } 
   } 
}

Клиентская программа

Ниже приведена клиентская программа этого приложения. Здесь мы выбираем удаленный объект и вызываем метод с именем getStudents () . Он извлекает записи таблицы из объекта списка и отображает их.

import java.rmi.registry.LocateRegistry; 
import java.rmi.registry.Registry; 
import java.util.*;  

public class Client {  
   private Client() {}  
   public static void main(String[] args)throws Exception {  
      try { 
         // Getting the registry 
         Registry registry = LocateRegistry.getRegistry(null); 
    
         // Looking up the registry for the remote object 
         Hello stub = (Hello) registry.lookup("Hello"); 
    
         // Calling the remote method using the obtained object 
         List<Student> list = (List)stub.getStudents(); 
         for (Student s:list)v { 
            
            // System.out.println("bc "+s.getBranch()); 
            System.out.println("ID: " + s.getId()); 
            System.out.println("name: " + s.getName()); 
            System.out.println("branch: " + s.getBranch()); 
            System.out.println("percent: " + s.getPercent()); 
            System.out.println("email: " + s.getEmail()); 
         }  
      // System.out.println(list); 
      } catch (Exception e) { 
         System.err.println("Client exception: " + e.toString()); 
         e.printStackTrace(); 
      } 
   } 
}

Шаги для запуска примера

Ниже приведены шаги для запуска нашего примера RMI.

Шаг 1 – Откройте папку, в которой вы сохранили все программы, и скомпилируйте все файлы Java, как показано ниже.

Javac *.java   

Хранимые Программы

Шаг 2 – Запустите реестр rmi, используя следующую команду.

start rmiregistry

Начать выполнение

Это запустит реестр rmi в отдельном окне, как показано ниже.

Отдельное окно

Шаг 3 – Запустите файл класса сервера, как показано ниже.

Java Server

Запустить сервер

Шаг 4 – Запустите файл класса клиента, как показано ниже.

java Client

Java RMI (Remote Method Invocationудаленный вызов методов) представляет собой тип удаленного вызова процедур, независимый от сети, облегченный и полностью переносимый, так как написан на языке Java.

Технология RMI основана на более ранней подобной технологии RPC (Remote Procedure Call удаленного вызова процедур) для процедурного программирования, разработанной в 80-х годах. RPC позволяет процедуре вызывать функцию на другом компьютере столь же легко, как если бы эта функция была частью программы, выполняющейся на том же компьютере. Для устранения недостатков RPC была разработана технология RMI, которая обслуживает маршалинг данных через сеть и дает возможность программам на Java передавать законченные объекты Java с помощью механизма сериализации объектов Java.

Сериализация — это процесс сохранения состояния объекта в последовательность байт; десериализация это процесс восстановления объекта, из этих байт. Java Serialization API предоставляет стандартный механизм для создания сериализуемых объектов.

Маршалинг — по смыслу похож на сериализацию, процесс преобразования представления объекта в памяти в формат данных, пригодный для хранения или передачи. Применительно же к компьютерным сетям, маршалинг означает процесс упаковки данных и преобразования их в стандартный вид перед передачей по сети так, чтобы данные могли пройти через сетевые ограничители. Чтобы передать объект во внешнюю сеть, он должен быть преобразован в поток данных, соответствующий структуре пакетов сетевого протокола. Части данных содержатся в буфере до того момента, пока не будут упакованы. Когда данные переданы, компьютер-получатель преобразует упакованные данные обратно в объект.

1 Основные шаги работы с RMI

Для реализации приложения, основанного на RMI, необходимо выполнить определённую последовательность действий:

  1. Определить удаленный интерфейс, согласованный с сервером.
  2. Написать код сервера.
  3. Запустить программу rmic (Java RMI stub compilerкомпилятор заглушек RMI) для генерации связующего кода.
  4. Написать код клиента.
  5. Убедиться, что на сервере запущен RMI реестр (программа rmiregistry).
  6. Запустить сервер.
  7. Запустить одного или нескольких клиентов.

2 Удалённый интерфейс

Процедуры RMI определяют с помощью известного механизма Java – интерфейсов.

Интерфейс имеет следующий общий синтаксис [5]:

// Заголовок интерфейса
<модификатор доступа> interface <имя интерфейса> <extends выражение>

// Тело интерфейса
<объявления констант>
<объявления прототипов методов>
<объявления вложенных классов>
<объявления вложенных интерфейсов>

Примечание: Интерфейс не предоставляет никакой реализации, поэтому является абстрактным по определению. Это означает, что нельзя создать его экземпляр, но классы могут его реализовывать, предоставляя реализацию для его прототипов методов.

Удаленные интерфейсы должны быть подклассами java.rmi.Remote, при этом и клиент и сервер должны находиться в одном пакете Java. Все параметры удаленных методов должны относиться или к примитивным типам (int, double и т.п.), либо реализовывать интерфейс java.io.Serializable. Каждый метод удаленного интерфейса должен декларировать java.rmi.RemoteException в своем разделе throws в дополнение ко всем остальным специфичным для приложения исключениям.

Пример удалённого интерфейса, который предоставляет службу точного времени:

// интерфейс системы точного времени
import java.rmi.*;
public interface PerfectTimeI extends Remote {
  long getPerfectTime() throws RemoteException;
}

3 Реализация удалённого интерфейса (серверная часть)

Сервер должен содержать класс, который наследуется от UnicastRemoteObject (extends UnicastRemoteObject) и реализует удаленный интерфейс (implements имя интерфейса). Этот класс может также иметь дополнительные методы, но для клиента будут доступны только методы удаленного интерфейса, так как клиент будет получать только ссылку на интерфейс, а не на класс, реализующий его.

Пример реализации удаленного интерфейса PerfectTimeI:

import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;
import java.net.*;

public class PerfectTime extends UnicastRemoteObject implements PerfectTimeI {
  // Реализация интерфейса:
  public long getPerfectTime() throws RemoteException {
    return System.currentTimeMillis();
  }

  // Конструктор, выбрасывающий RemoteException
  public PerfectTime() throws RemoteException {
    super(); // вызывается автоматически
  }

  // Запуск удалённого объекта, который
  // выбрасывает исключения на консоль
  public static void main(String[] args) throws Exception {
    System.out.println("Initializing PerfectTime…");

    // Менеджер безопасности, который поддерживает RMI:
    System.setSecurityManager(new RMISecurityManager());

    // Создание удалённого объекта
    PerfectTime pt = new PerfectTime();

    // Регистрация удалённого объекта PerfectTime в реестре rmiregistry
    Naming.bind("rmi://localhost:2000/PerfectTime", pt);
    System.out.println("Ready to do time");
  }
}

Класс UnicastRemoteObject (пакет java.rmi.server) предоставляет удалённым объектам базовые функциональные возможности для обслуживания удалённых запросов. Конструкторы и методы класса UnicastRemoteObject возбуждают контролируемое исключение RemoteException, поэтому его подклассы должны определять конструкторы, также возбуждающие исключение RemoteException. По этой причине в подклассе необходимо явно определить конструктор для удаленного объекта, даже если определён только конструктор по умолчанию, который вызывает конструктор базового класса.

Конструктор класса UnicastRemoteObject экспортирует объект, чтобы сделать его доступным для приёма удалённых вызовов. Экспорт объекта даёт возможность удалённому объекту ожидать соединений с клиентами через анонимный порт. Это даёт возможность объекту осуществлять однонаправленное взаимодействие (посредством вызова методов) с использованием сокетов.

4 Настройка реестра

Реестр RMI обслуживается утилитой rmiregistry, и должен быть запущен как отдельный процесс на компьютере. Однако, если наше приложение является единственным, использующим реестр, его можно запускать в самой программе:

LocateRegistry.createRegistry(2000);

Для экспорта удалённого объекта необходимо определить URL , который клиент сможет использовать для получения удалённой ссылки на объект. URL обычно имеет следующий вид:

"rmi://хост:порт/имя удалённого объекта"

где хост – имя компьютера, который выполняет сервер реестра и на нём же выполняется удалённый объект, порт реестра RMI по умолчанию 1099, имя удалённого объекта будет использовать клиент для поиска удалённого объекта в реестре.

Если реестр выполняется на локальном компьютере, то можно использовать следующий URL:

"rmi://localhost/PerfectTime"

или

"PerfectTime"

Для связывания удалённого объекта с реестром используются статические методы Naming.bind() или Naming.rebind() класса Naming(пакета java.rmi). Разница между этими методами заключается в том, что если имя удалённого объекта уже есть в реестре, то bind() вызовет исключение AlreadyBoundException, а rebind() заменит существующую запись.

5 Заглушки и скелеты

Для обеспечения правильной работы RMI приложения необходимо создать заглушки и скелеты (вместо скелета используются также термины скелетон или каркас), обеспечивающие сетевое соединение. Для этого служит утилита rmic, входящая в состав Java 2 SE. После её запуска в папке с проектом должны быть созданы два класса _Stub.class и _Skel.class. В нашем примере это будут:

PerfectTime_Stub.class
PerfectTime_Skel.class

6 Использование удалённого объекта (клиентская часть)

Клиент, как уже упоминалось выше, взаимодействует с публичным интерфейсом, а не с его реализацией, скрытой от конечного пользователя. Приведённый ниже пример демонстрирует вызов метода getPerfectTime() удалённого объекта PerfectTime, для получения системного времени последнего через интерфейс PerfectTimeI.

// Использование удаленного объекта PerfectTime
import java.rmi.*;
import java.rmi.registry.*;
public class DisplayPerfectTime {
  public static void main(String[] args) throws Exception {
    System.setSecurityManager(new RMISecurityManager());
    PerfectTimeI t = (PerfectTimeI) Naming.lookup("PerfectTime");
    for (int i = 0; i < 10; i++)
      System.out.println("Perfect time = " + t.getPerfectTime());
  }
}

Для поиска в реестре удалённого объекта PerfectTime используется статический метод Naming.lookup() (пакета java.rmi).

7 Запуск приложения

Для работы приложения необходимо проделать последовательность действий, описанную в разделе 1. После того, как написан код приложений, произведена настройка реестра, созданы заглушки и скелеты запускается сначала серверная часть, а затем клиентская – работа сделана.

  • Java

Начало работы с Java RMI

1. обзор

Когда две JVM должны общаться, Java RMI — это один из вариантов, который нам нужен для этого. В этой статье мы рассмотрим простой пример, демонстрирующий технологию Java RMI.

2. Создание сервера

Для создания RMI-сервера необходимо выполнить два шага:

  1. Создайте интерфейс, определяющий контракт клиент / сервер.

  2. Создайте реализацию этого интерфейса.

2.1. Определение контракта

Прежде всего, создадим интерфейс для удаленного объекта. Этот интерфейс расширяет интерфейс маркераjava.rmi.Remote.

Кроме того, каждый метод, объявленный в интерфейсе, выдаетjava.rmi.RemoteException:

public interface MessengerService extends Remote {
    String sendMessage(String clientMessage) throws RemoteException;
}

Однако обратите внимание, что RMI поддерживает полную спецификацию Java для сигнатур методов, если типы Java реализуютjava.io.Serializable.

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

Для сервера мы создадим реализацию, которую часто называютRemote Object.

Для клиентаthe RMI library will dynamically create an implementation called a Stub.

2.2. Реализация

Кроме того, давайте реализуем удаленный интерфейс, снова называемыйRemote Object:

public class MessengerServiceImpl implements MessengerService {

    @Override
    public String sendMessage(String clientMessage) {
        return "Client Message".equals(clientMessage) ? "Server Message" : null;
    }

    public String unexposedMethod() { /* code */ }
}

Обратите внимание, что мы исключили предложениеthrowsRemoteException из определения метода.

Было бы необычно, если бы наш удаленный объект выдалRemoteException, поскольку это исключение обычно зарезервировано для библиотеки RMI, чтобы вызывать ошибки связи с клиентом.

Отказ от этого также имеет преимущество в том, что наша реализация не зависит от RMI.

Такжеany additional methods defined in the remote object, but not in the interface, remain invisible for the client.

3. Регистрация Сервиса

После создания удаленной реализации нам нужно привязать удаленный объект к реестру RMI.

3.1. Создание заглушки

Сначала нам нужно создать заглушку нашего удаленного объекта:

MessengerService server = new MessengerServiceImpl();
MessengerService stub = (MessengerService) UnicastRemoteObject
  .exportObject((MessengerService) server, 0);

Мы используем статический методUnicastRemoteObject.exportObject для создания нашей реализации-заглушки. The stub is what does the magic of communicating with the server over the underlying RMI protocol.

Первый аргументexportObject — это объект удаленного сервера.

Второй аргумент — это порт, которыйexportObject использует для экспорта удаленного объекта в реестр.

Нулевое значение указывает на то, что нам все равно, какой портexportObject использует, что является типичным и поэтому выбирается динамически.

К сожалению, методexportObject() без номера порта устарел.

3.2 Creating a Registry

Мы можем создать реестр локально для нашего сервера или как отдельную отдельную службу.

Для простоты мы создадим локальный по отношению к нашему серверу:

Registry registry = LocateRegistry.createRegistry(1099);

Это создает реестр, к которому заглушки могут быть привязаны серверами и обнаружены клиентами.

Кроме того, мы использовали методcreateRegistry, поскольку мы создаем реестр локально для сервера.

По умолчанию реестр RMI работает на порту 1099. Скорее, другой порт также можно указать в фабричном методеcreateRegistry.

Но в автономном случае мы вызываемgetRegistry, передавая имя хоста и номер порта в качестве параметров.

3.3 Binding the Stub

Следовательно, привяжем нашу заглушку к реестру. Реестр RMI — это средство именования, такое как JNDI и т. Д. Здесь мы можем следовать аналогичной схеме, привязывая нашу заглушку к уникальному ключу:

registry.rebind("MessengerService", stub);

В результате удаленный объект теперь доступен любому клиенту, который может найти реестр.

4. Создание клиента

Наконец, давайте напишем клиенту для вызова удаленных методов.

Для этого сначала нужно найти реестр RMI. Кроме того, мы будем искать заглушку удаленного объекта, используя ограниченный уникальный ключ.

И наконец, вызовем методsendMessage:

Registry registry = LocateRegistry.getRegistry();
MessengerService server = (MessengerService) registry
  .lookup("MessengerService");
String responseMessage = server.sendMessage("Client Message");
String expectedMessage = "Server Message";

assertEquals(expectedMessage, responseMessage);

Поскольку мы запускаем реестр RMI на локальном компьютере и порт по умолчанию 1099, мы не передаем никаких параметров вgetRegistry.

Действительно, если реестр находится скорее на другом хосте или другом порту, мы можем предоставить эти параметры.

Как только мы ищем объект-заглушку с помощью реестра, мы можем вызвать методы на удаленном сервере.

5. Заключение

В этом руководстве мы получили краткое представление о Java RMI и о том, как оно может стать основой для клиент-серверных приложений. Следите за новостями о некоторых уникальных функциях RMI!

Исходный код этого руководства находится вon GitHub.

Удаленный вызов метода – это способ, которым программист использует язык программирования Java и его среду разработки удаленно.

RMI (Remote Method Invocation) – это API, который предоставляет механизм для создания распределенного приложения на Java. RMI позволяет объекту вызывать методы объекта, запущенного в другой JVM. Удаленный вызов метода обеспечивает удаленную связь между приложениями с использованием двух объектов.

Объект-заглушка на клиентском компьютере создает информационный блок и отправляет эту информацию на сервер. Блок состоит из:

  • Идентификатор удаленного объекта, который будет использоваться;
  • Имя метода, который должен быть вызван;
  • Параметры для удаленной JVM.

rmi в Java

Скелетный объект передает запрос от объекта-заглушки к удаленному объекту. Он выполняет следующие задачи:

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

Теперь рассмотрим шаги для создания приложения RMI.

Шаг 1: Определение удаленного интерфейса

Первое, что нам нужно сделать, это создать интерфейс. Это предоставит описание методов, которые могут быть вызваны удаленными клиентами. Этот интерфейс должен расширять интерфейс Remote, а прототип метода в интерфейсе должен выдавать исключение RemoteException.

// Creating a Search interface
import java.rmi.*;
public interface Search extends Remote{
// Declaring the method prototype
public String Query(String search) throws RemoteException;
}

Шаг 2: Реализация удаленного интерфейса

Следующим шагом является реализация удаленного интерфейса. Для реализации удаленного интерфейса класс должен быть расширен до класса UnicastRemoteObject пакета java.rmi. Кроме того, конструктор по умолчанию должен быть создан для выброса java.rmi.RemoteException от его родительского конструктора.

// Java program to implement the Search interface
import java.rmi.*;
import java.rmi.server.*;
public class SearchQuery extends UnicastRemoteObject implements Search{
// Default constructor to throw RemoteExceptionnbsp;from its parent constructor
SearchQuery() throws RemoteException{
super();
}// Implementation of the query interface
public String query(String search) throws RemoteException{
String result;
if (search.equals("Reflection in Java"))
result = "true";
else
result = "false";
return result;
}
}

Шаг 3: Создание объектов Stub и Skeleton из класса реализации с использованием rmic

Инструмент RMIC используется для вызова компилятора RMI, который создает объекты Stub и Skeleton. Его прототип – имя класса RMIC.

ШАГ 4: Запустите RMIregistry

Чтобы запустить службу реестра, введите в командной строке команду запуска RMIregistry.

ШАГ 5. Создание и выполнение прикладной программы сервера

Следующим шагом является создание прикладной программы сервера и ее выполнение в отдельной командной строке.

  • Программа сервера использует метод createRegistry класса LocateRegistry для создания rmiregistry в JVM сервера с номером порта, передаваемым в качестве аргумента.
  • Метод rebind класса Naming используется для привязки удаленного объекта к новому имени.
//program for server application
import java.rmi.*;
import java.rmi.registry.*;
public class SearchServer{
public static void main(String args[]){
try{
// Create an object of the interface implementation class
Search obj = new SearchQuery();

// rmiregistry within the server JVM with
// port number 1900
LocateRegistry.createRegistry(1900);
lt;p style="text-align: justify;"gt;// Binds the remote object by the name
//edureka
Naming.rebind("rmi://localhost:1900"+
"/edureka",obj);
}
catch(Exception ae){
System.out.println(ae);
}
}
}

Шаг 6. Создание и выполнение программы клиентского приложения

Последний шаг – создание программы клиентского приложения и ее выполнение в отдельной командной строке. Метод lookup класса Naming используется для получения ссылки на объект Stub

Вышеуказанная клиентская и серверная программа выполняется на одной машине, поэтому используется localhost. Чтобы получить доступ к удаленному объекту с другого компьютера, локальный хост должен быть заменен IP-адресом, на котором находится удаленный объект.

Improve Article

Save Article

  • Read
  • Discuss
  • Improve Article

    Save Article

    Prerequisite: RMI

    RMI (Remote Method Invocation) is used for distributed object references system. A distributed object is an object which publishes its interface on other machines. A Remote Object is a distributed object whose state is encapsulated. Stub and Skeleton are two objects used to communicate with the remote object.

    Stub: Stub is a gateway for client program which is used to communicate with skeleton object, by establishing a connection between them.

    Skeleton: Resides on Server program which is used for passing the request from stub to the remote interface.

    How communication and process takes place in RMI:

    Steps to Run Java RMI Application in Console

    1. Creation of classes and interfaces for the problem statement: The steps involved in this are as follows:
      • Create a Remote Interface which extends java.rmi.Remote:

        A remote interface determines the object that can be invoked remotely by the client. This interface can be communicated with the client’s program. This Interface must extend java.rmi.Remote Interface.

        Problem Statement: Create an RMI Application for finding the factorial of a number

        Interface Program

        import java.math.BigInteger;

        public interface Factorial

            extends java.rmi.Remote {

            public BigInteger fact(int num)

                throws java.rmi.RemoteException;

        }

      • Create a class which extends java.rmi.server.UnicastRemoteObject and implements the previous interface.

        This class will implement the remote interface. Do the required calculation for the problem statement.

        Implementation of Interface

        import java.math.BigInteger;

        public class FactorialImpl

            extends java.rmi.server.UnicastRemoteObject

            implements Factorial {

            public FactorialImpl()

                throws java.rmi.RemoteException

            {

                super();

            }

            public BigInteger fact(int num)

                throws java.rmi.RemoteException

            {

                BigInteger factorial = BigInteger.ONE;

                for (int i = 1; i <= num; ++i) {

                    factorial = factorial

                                    .multiply(

                                        BigInteger

                                            .valueOf(i));

                }

                return factorial;

            }

        }

      • Create a Server Class (with localhost and service name)

        For hosting a service, the server program is created whereby using java.rmi.Naming.rebind() method can be called which takes two arguments i.e., an object reference (service name) and instances reference.

        Server Program

        import java.rmi.Naming;

        public class FactorialServer {

            public FactorialServer()

            {

                try {

                    Factorial c = new FactorialImpl();

                    Naming.rebind("rmi:// localhost/FactorialService", c);

                }

                catch (Exception e) {

                    System.out.println("ERR: " + e);

                }

            }

            public static void main(String[] args)

            {

                new FactorialServer();

            }

        }

      • Create a Client Class (with localhost and service name)

        Client program will invokes java.rmi.Naming.lookup() method for RMI URL and returns an instance of object type (Factorial Interface). All RMI is done on this object

        Client Program

        import java.net.MalformedURLException;

        import java.rmi.Naming;

        import java.rmi.NotBoundException;

        import java.rmi.RemoteException;

        public class FactorialClient {

            public static void main(String[] args)

            {

                try {

                    Factorial c = (Factorial);

                    Naming.lookup("rmi:// localhost/FactorialService");

                    System.out.println(c.fact(30));

                }

                catch (MalformedURLException murle) {

                    System.out.println("nMalformedURLException: "

                                       + murle);

                }

                catch (RemoteException re) {

                    System.out.println("nRemoteException: "

                                       + re);

                }

                catch (NotBoundException nbe) {

                    System.out.println("nNotBoundException: "

                                       + nbe);

                }

                catch (java.lang.ArithmeticException ae) {

                    System.out.println("nArithmeticException: " + ae);

                }

            }

        }

    2. Compilation of all program

      Use javac to compile all four programs and rmic (RMI Compiler) to create a stub and skeleton class files.

    3. Running the system:

      After the compilation phase, the system is now ready to run. To run the system, open three console screen (move to that path where the program resides). One for the client, one for server and one for the RMI Registry.

      • Start with a registry, use rmiregistry, if there is no error registry will start running and now move to second screen.

      • In the second console run the server program and host the FactorialService. It will start and wait for the client connection and it will load the implementation into memory.

      • In the third console, run the client program.

    In this way RMI can be run in three console for localhost. RMI uses Network stack and TCP/IP Stack for communication of three different JVM’s.

    Понравилась статья? Поделить с друзьями:
  • Как написать report на английском образец
  • Как написать reference letter
  • Как написать readme github
  • Как написать psytrance
  • Как написать proposal на английском пример