63315

Удаленный интерфейс. Remote Method Invocation

Лекция

Информатика, кибернетика и программирование

Традиционный подход к выполнению на удаленной машине сбивал с толку, а также был утомителен и подвержен ошибкам при реализации. Лучший способ представить эту проблему – это думать, что какой-то объект живет на другой машине, и что вы можете посылать сообщения удаленному объекту и получать результат, будто бы объект живет на вашей машине.

Русский

2014-06-19

66.5 KB

1 чел.

  1.  Remote Method Invocation    

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

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

RMI большей частью использует интерфейсы. При создании своего удаленного объекта вы скрываете его низкоуровневую реализацию, передавая ссылку на его интерфейс. Таким образом, когда удаленный клиент получает ссылку на объект, на самом деле он получает ссылку на интерфейс, который по некоторой причине оказывается подсоединенным к локальному коду – “заглушке”, который и производит переговоры по сети. Но вы не заботитесь об этом, вы просто посылаете сообщения через ссылку на  интерфейс.    

Когда вы создаете удаленный  интерфейс, вы должны следовать следующей инструкции:

  1.  Удаленный  интерфейс должен быть открытым – public (он не должен иметь “доступ на уровне пакета”, так же он не может быть “дружественным”). В противном случае клиенты будут получать ошибку при попытке загрузки удаленного объекта, реализующего удаленный  интерфейс.
  2.  Удаленный  интерфейс должен расширять интерфейс, java.rmi.Remote.
  3.  Каждый метод удаленного интерфейса должен объявлять java.rmi.              RemoteException в своем предложении throws вдобавок к любым исключениям, специфичным для вашего приложения.
  4.  Удаленный объект, передаваемый как аргумент или возвращаемое значение (прямо или косвенно как объект – член локального объекта), должен быть объявлен как удаленный  интерфейс, а не как класс с реализацией.
Ниже приведен простой удаленный  интерфейс, представляющий сервис точного времени:
import java.rmi.* ;
interface PerfectTimeI extends Remote {
        long  getPerfectTime () throws RemoteException;
Он выглядит как любой другой интерфейс, за исключением того, что расширяет  другой интерфейс Remote и все его методы выбрасывают RemoteException. Помните, что интерфейс и все его методы автоматически становятся public.
 
Реализация удаленного  интерфейса
Сервер должен содержать класс, который расширяет UnicastRemoteObject и реализует удаленный  интерфейс. Этот класс также может иметь другие методы, но для клиента доступны только методы удаленного  интерфейса, так как клиент получает ссылку только на удаленный  интерфейс, а не на класс, который его реализует.
Вы должны явно определить конструктор для удаленного объекта, даже если вы определяете конструктор по умолчанию, который вызывает конструктор базового класса. Вы должны написать его, так как он должен выбрасывать RemoteException.
Ниже приведена реализация удаленного интерфейса PerfectTimeI:
import  java.rmi.* ;
import  java.rmi.server.* ;
import  java.rmi.registry.* ;
import  java.rmi.net.* ;
public class PerfectTime extends UnicastRemoteObject implements PerfectTimeI {
         // Реализация интерфейса:
        public long getPerfectTime () throws  RemoteException {
                 return System.currentTimeMillis ();
        }
        //  Должна быть реализация конструктора
        //  для выбрасывания RemoteException :
      public PerfectTime () throw RemoteException {
                // super (); // вызывается автоматически
      }
      //  Регистрация для обслуживания RMI. Выбрасывает 
      //  исключения на консоль.
      Public static void main (String [] args) throws  Exception {
               System.setSecurityManager (new RMISecurityManager ());
               PerfectTime pt = new PerfectTime ();
               Naming.bind (“//Ready to do time”);
      }
 }
В   этом примере main () обрабатывет все установки сервера. Когда вы обслуживаете RMI объект, в определенном месте вашей программы вы должны:
  1.  Создать и установить менеджер безопасности, поддерживающий сервисы RMI. Как часть Java пакета, для RMI поддерживается только RMISecurityManager.
  2.  Создать один или несколько экземпляров удаленного объекта. Здесь вы видите создание объекта PerfectTime.
  3.  Зарегистрировать не менее одного удаленного объекта в реестре удаленных объектов RMI, чтобы в последствии ими можно было пользоваться. Этот удаленный объект может иметь методы, которые производят ссылки на другие удаленные объекты. Их также можно зарегистрировать в реестре, чтобы клиенту не пришлось обращаться к нему много раз.
Установка реестра
В рассмотренном примере вызывался статический метод Naming.bind(). Однако для вызова этого метода требуется, чтобы реестр был запущен отдельным процессом на вашем компьютере. Имя сервера реестра – это rmiregistry, и для запуска под 32-битной Windows необходимо выполнить следующую команду:
start rmiregistry
              port 1099
для запуска его в качестве фонового процесса или  start rmiregistry 2005
Как и многие другие сетевые программы, сервер rmiregistry располагается по IP адресу машины, с которой его установили, но он также должен прослушивать порт под определенным порядковым номером. Если вы вызовите rmiregistry как показано выше, без аргументов, будет использован порт по умолчанию 1099. Если вы хотите использовать другой порт, вы добавляете аргумент в командную строку, указывающий порт. Следующий пример устанавливает порт 2005, поэтому rmiregistry под управлением 32-битной Windows должен запускаться так:
start rmiregistry 2005
Информацию о порте также необходимо передать в метод bind(), наряду с IP адресом машины, где располагается сервер реестра. Но при попытке использовать локальный IP-адрес, как это делается при тестировании сетевых программ, возникает досадная проблема. В JDK 1.1.1 существовала пара таких проблем:
  1.  Локальный IP-адрес localhost не работает с библиотекой RMI. Поэтому для экспериментов с RMI на одной машине вы должны использовать настоящее имя машины.
  2.  Библиотека RMI не станет функционировать, пока у вас не будет настоящего TCP/IP соединения, даже если все ваши компоненты просто общаются друг с другом на одной машине. Это значит, что вы должны соединиться с вашим Internet-провайдером до того, как попробуете запустить программу, иначе возникнут странные сообщения об ошибках.
Если учесть все это, команда bind () примет вид:
Naming.bind (“//peppy: 2005/PerfectTime”, pt);

Если вы используете порт по умолчанию 1099, вам не нужно указывать порт, так что вы можете просто сказать:

Naming.bind("//peppy/PerfectTime", pt);

Вы можете выполнить локальную проверку оставив в покое IP адрес, а использовать только идентификатор:

Naming.bind("PerfectTime", pt);

Имя сервиса здесь произвольно. В данном случае PerfectTime выбрано просто как имя класса, но вы можете назвать так, как захотите. Важно, чтобы это было уникальное имя регистрации, чтобы клиент знал имя, когда будет искать определенный удаленный объект. Если имя уже зарегистрировано, вы получите AlreadyBoundException. Чтобы предотвратить это, вы всегда можете использовать rebind () вместо bind (), так как rebind () либо добавляет новый элемент, либо заменяет уже существующий.

Даже после завершения работы main(), ваш объект остается существовать в реестре, ожидая, что придет клиент и выполнит запрос. Пока rmiregistry остается запущенным, и вы не вызовите Naming, unbind () на вашей машине, объект будет оставаться там. По этой причине, при отладке вашего кода необходимо выгружать rmiregistry и перезапускать его, когда скомпилируете новую версию вашего удаленного объекта.

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

 LocateRegistry.createRegistry(2005);

Как и раньше, 2005 - это номер порта, который использовался в этом примере. Это эквивалентно запуску rmiregistry 2005 из командной строки, но часто этот способ является более удобным при разработке RMI-приложений, так как это снижает число необходимых действий при запуске и остановке реестра. После того, как вы выполните этот код, вы можете вызвать Naming. bind (), как и ранее.

Создание заглушек и каркасов

Если вы откомпилируете и запустили PerfectTime . Java, оно не будет работать, даже если вы правильно запустили rmiregistry. Это происходит потому, что основного каркаса библиотеки RMI еще не создано. Вы должны сначала создать заглушки и каркасы, которые обеспечат работу сетевого соединения и позволят вам делать вид, что удаленный объект - это просто локальный объект на вашей машине.

То, что происходит за сценой - очень сложно. Любой объект, который вы передаете или получаете из удаленного объекта, должен реализовывать(1тр!етеп1) Serializable (если вы хотите передавать удаленные ссылки вместо целых объектов, аргументы объектов могут реализовывать Remote), так что вы можете представить, как заглушки и каркасы автоматически выполняют сериализацию и десериализацию во время | «упаковки» параметров методов и возвращаемых результатов. К счастью, вам не нужно знать всего этого, но вы должны создавать заглушки и каркасы. Это простой процесс: вы вызываете инструмент rmic для вашего откомпилированного кода, а он создает необходимые файлы. Так что от вас требуется включить еще один шаг в процесс компиляции.

PerfectTime.java находится в пакете clS.rmi:

rmic c!5.rmi.PerfectTime

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

Когда выполнение программы rmic завершится успешно, вы найдете два новых класса в директории:

PerfectTime_Stub.class

PerfectTime_Skel.class

соответствующих заглушке и каркасу. Теперь вы готовы запустить общение клиента с сервером.

Использование удаленных объектов

Главная цель RMI состоит в упрощении использования удаленных объектов. Вы должны сделать только самую важную вещь в вашей клиентской программе: это поиск и получение удаленного интерфейса с сервера. Во всем остальном - это обычное программирование на Java: посылка сообщений объекту. Ниже приведена программа, использующая PerfectTime:

import java.rmi.*;

import Java . rmi . registry .*;

public class DisplayPerfectTime {

           public static void main (String [] args) throws Exception {

           System.setSecurityManager (new RMISecurityManager ()) ;

             PerfectTimel t = (PerfectTimel ) Naming. lookup (

     "//peppy: 2005/PerfectTime") ;

for(int i = 0; i < 10; i++)

                  System. out . println ( "Perfect time = " +

                        t . getPerf ectTime (

                }

        } ;

Использованный идентификатор совпадает с тем, что использовался при регистрации объекта в реестре помощью Naming, а первая часть представляет URL и номер порта. Так как вы используете URL, вы можете также указать любую машину в Internet.

То, что возвращается из Naming, lookup () должно быть преобразовано к удаленному интерфейсу, а не к классу. Если вы будите использовать класс, вы получите исключение.

Вы можете видеть, что вызов удаленного метода

t.getPerfectTime ( )

ничем не отличается от вызова метода любого локального объекта. Как только вы получаете ссылку на удаленный объект, программирование с ним ничем не отличается от программирования с локальными объектами (за одним исключением: удаленные методы способны возбуждать исключение RemoteException.


 

А также другие работы, которые могут Вас заинтересовать

51622. Властивості степенів з натуральним показником 75.5 KB
  Тип уроку : урок застосування отриманих умінь і навичок інтерактивний урок Інтерактивні технології : вирішення проблеми аналіз ситуації займи позицію оцінювальна дискусія Обладнання : підручники збірники задач таблиці інтерактивна дошка диференційовані завдання роздатковий матеріал завдання на картках контрольні запитання Зміст урок Організаційний момент. Перевірка домашнього завдання...
51624. Это я, это я, это все мои друзья 35 KB
  У меня руки чистые я только что их вымыл с мылом Ты не мог их вымыть с мылом потому что первоклассник Пупкин на перемене съел мыло и его отвезли в больницу. Ну правильно я попросил мыло у завхоза. Он не мог тебе дать мыло потому что в стране дефицит и мыло выдают по талонам а у завхоза строгий учет Я подкупил завхоза бутылкой спиртного Гражданам СССР не достигшим 21 года спиртные напитки не отпускаются А у меня папа директор ликеро водочного завода.