3. RMI — Удаленный вызов методов на Java

  • В этой теме 0 ответов, 1 участник, последнее обновление 1 месяц, 1 неделя назад сделано Васильев Владимир Сергеевич.
Просмотр 0 веток ответов
  • Автор
    Сообщения
    • #6346
      @admin

      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. После того, как написан код приложений, произведена настройка реестра, созданы заглушки и скелеты запускается сначала серверная часть, а затем клиентская – работа сделана.

Просмотр 0 веток ответов
  • Для ответа в этой теме необходимо авторизоваться.