Sistemas
Distribuídos
Marcelo Lobosco
DCC/UFJF
Comunicação em
Sistemas Distribuídos
Aula 06
Agenda
Modelo Cliente-Servidor (cont.)
Invocação
Remota de Método (Remote
Method Invocation – RMI)
Visão Geral
Criando aplicações distribuídas com RMI
Escrevendo código do servidor
Escrevendo código do cliente
Compilando e executando o exemplo
Visão Geral
RMI provê suporte para comunicação
remota entre programas escritos na
linguagem de programação Java
Java
RMI permite que um objeto executando
em uma Máquina Virtual Java (MVJ) invoque
métodos de um objeto executando em uma
segunda MVJ
Aplicações RMI geralmente consistem de
dois programas separados
Cliente
e servidor
Visão Geral
Típico programa servidor cria algum(ns) objeto(s)
remoto(s), torna a(s) referência(s) a este(s)
objeto(s) acessível(ies) e aguarda o(s) cliente(s)
invocarem métodos neste(s) objeto(s)
Típico programa cliente obtêm uma referência
remota para um ou mais objetos remotos em um
servidor e então invoca métodos neste(s)
RMI provê o mecanismo pelo qual clientes e
servidores se comunicam e passa informações
de um lado para o outro
Visão Geral
Tais
aplicações algumas vezes chamadas
sistemas de objetos distribuídos (OD).
Ações necessárias em um sistema de OD:
Localizar
os objetos remotos
Comunicar com objetos remotos
Ler definições de classes para objetos que são
passados como parâmetro / retorno
Visão Geral
Localizar
objetos remotos
Vários
mecanismos podem ser utilizados para
obter referência de objetos remotos
Aplicação pode registrar seus objetos remotos em
um serviço especial de registro de nomes, RMI
registry
Referências remotas podem ser passadas /
retornadas como parte de invocações remotas
Comunicar
com objetos remotos
Detalhes
da comunicação com objetos
remotos são tratados por RMI
Para programador, comunicação remota similar a
invocação tradicional de métodos
Visão Geral
Ler definições de classes para objetos que
são passados como parâmetro / retorno
RMI
permite que objetos sejam passados
como parâmetro / retorno
RMI provê mecanismos para ler definição da
classe de um objeto
Java é uma linguagem dinâmica
RMI
provê mecanismos para transmitir estado
de um objeto
Visão Geral
Visão Geral
Figura ilustra aplicação RMI distribuída que
usa registro para obter referência para
objeto remoto
Servidor
chama registro para associar (ou ligar
– bind) um nome a um objeto remoto
Cliente procura por objeto remoto pelo seu
nome no registro do servidor e então invoca
um método neste objeto
Webserver pode ser usado por sistema RMI
para ler definição de classes para objetos
necessários
Tanto do lado do cliente quanto do servidor
Visão Geral
Interfaces, objetos e métodos remotos
Como
qualquer aplicação Java, aplicação
distribuída composta de classes e interfaces
Interfaces declaram métodos
Classes implementam métodos declarados na
interface, podendo declarar métodos adicionais
Em
uma aplicação distribuída, implementações
podem residir em máquinas virtuais distintas
Objetos com métodos que podem ser
invocados por diferentes MVJ são chamados
de objetos remotos
Visão Geral
Objeto torna-se remoto quando implementa
um interface remota, que possui as
seguintes características:
Uma
interface remota estende a interface
java.rmi.Remote
Cada método da interface declara
java.rmi.RemoteException em sua cláusula
throws, em adição a qualquer exceção
específica da aplicação
Visão Geral
RMI trata objetos remotos de forma distinta dos
objetos locais quando o objeto é passado de uma
MVJ para outra
Ao
invés de copiar na MVJ o objeto de
implementação invocado, RMI passa um stub
remoto para um objeto remoto
Stub age como representante local (proxy) do objeto
remoto
Basicamente stub é, para o cliente, a referência remota
Cliente invoca método no stub local, que é responsável
por repassar a chamada para o objeto remoto
Visão Geral
Stub para um objeto remoto implementa o
mesmo conjunto de interfaces remotas que
o objeto remoto implementa
Somente
métodos definidos na interface
remota podem ser chamadas pela MVJ onde
clientes executam
cliente
Máquina do cliente
stub
servid
or
Máquina do servidor
Criando Aplicações Distribuídas
com RMI
Passos gerais para desenvolver aplicação
distribuída com RMI:
Projetar
e implementar os componentes de sua
aplicação distribuída
Compilar os fontes
Tornar as classes acessíveis via rede
Iniciar a aplicação
Criando Aplicações Distribuídas
com RMI
Projetar e implementar os componentes de
sua aplicação distribuída
Inicialmente,
determine a arquitetura de sua
aplicação, definindo componentes locais e
componentes acessíveis remotamente:
Defina as interfaces remotas: especifica métodos
que podem ser invocados remotamente por um
cliente
Defina tipos dos parâmetros e retorno dos métodos
Implemente os objetos remotos: objetos remotos
devem implementar uma ou mais interfaces
Podem incluir implementações de interfaces e métodos
disponíveis apenas localmente
Criando Aplicações Distribuídas
com RMI
Projetar e implementar os componentes de sua
aplicação distribuída (cont)
Implemente o(s) clientes
Compile os fontes
qualquer programa java, use javac para
compilar os programas fonte
Como
Declarações de interfaces remotas, suas
implementações, outras classes de serviço, clientes
Versões anteriores a JSE 5.0 necessitam do rmic
Criando Aplicações Distribuídas
com RMI
Tornar as classes acessíveis via rede
Neste
passo, torne certas definições de
classes acessíveis via rede
Como definições para interfaces remotas e seus
tipos associados, e definições de classes que
precisam ser acessadas por clientes e servidores
Geralmente tornam-se acessíveis através de um
servidor web
Iniciar a aplicação
Inclui,
além do cliente e do servidor, o serviço
de registro de nomes, rmiregistry
Criando Aplicações Distribuídas
com RMI
Passagem de parâmetros
Qualquer
tipo primitivo, objeto remoto ou
objeto local, pode ser passado como
parâmetro em chamadas RMI
No caso de objeto local, além de acessível via
rede, deve ser também serializável
Para objeto ser considerado “serializável”, sua
classe deve implementar a interface
java.io.Serializable
Exemplo de Aplicação:
Calculadora Distribuída
Servidor oferece serviços de uma calculadora
Funcionalidade
simples: soma, subtração,
multiplicação e divisão com dois inteiros
Cliente faz uso dos serviços
Faz
invocação, passando parâmetros e
imprimindo resultado
Objetivo: ilustrar o funcionamento de RMI
Naturalmente
aplicação real
que overhead proibitivo para
Serviço muito simples
Calculadora Distribuída:
Interface
Primeiro passo: projetar interface remota
Que
serviços serão oferecidos?
Quais os parâmetros necessários?
Quais os tipos dos valores retornados?
Quais exceções podem ocorrer?
Calculadora Distribuída:
Interface
package exemplo;
import java.rmi.Remote;
import java.rmi.RemoteException;
import exemplo.divisaoPorZero;
public interface Calculadora extends Remote {
float som (float a, float b) throws
java.rmi.RemoteException;
float sub (float a, float b) throws
java.rmi.RemoteException;
float mul (float a, float b) throws
java.rmi.RemoteException;
float div (float a, float b) throws
DivisaoPorZero,
java.rmi.RemoteException;
}
Calculadora Distribuída:
Interface
Ao estender a interface java.rmi.Remote, a
interface Calculadora identifica-se como uma
interface que pode receber requisições de
outras MVJ
Qualquer
classe que implemente esta interface pode
produzir objetos remotos
Métodos da interface Calculadora podem ser
executados remotamente
Logo
devem ser capazes de sinalizar exceção
java.rmi.RemoteException
Sinaliza ocorrência de falha de comunicação ou
erro de protocolo
Calculadora Distribuída:
Implementação da Interface
De modo geral, classe que implementa
interface remota deve seguir, no mínimo,
os seguintes passos:
Declarar
as interfaces remotas sendo
implementadas
Definir o construtor para cada objeto remoto
Prover uma implementação para cada
método remoto declarado nas interfaces
remotas
Calculadora Distribuída:
Implementação da Interface
Programa servidor RMI deve:
Criar
os objetos remotos e
Exportá-los para o sistema runtime do RMI
Sistema runtime torna-os aptos a receber invocações remotas
Este processo de configuração pode ser:
Encapsulado
em um método da implementação da
interface remota ou
Incluído completamente em outra classe
Roteiro do processo de configuração:
Criar
e instalar um gerente de segurança
Criar e exportar um ou mais objetos remotos
Registrar ao menos um objeto remoto no registro de
nomes do RMI (ou outro serviço de nomes)
Calculadora Distribuída:
Implementação da Interface
package exemplo;
import
import
import
import
import
import
java.rmi.RemoteException;
java.rmi.registry.LocateRegistry;
java.rmi.registry.Registry;
java.rmi.server.UnicastRemoteObject;
exemplo.Calculadora;
exemplo.divisaoPorZero;
public class CalculadoraImpl implements Calculadora{
public CalculadoraImpl() {
super();
}
Calculadora Distribuída:
Implementação da Interface
public float som (float a, float b) {
return a+b;
}
public float sub (float a, float b) {
return a-b;
}
public float mul (float a, float b) {
return a*b;
}
public float div (float a, float b) throws
divisaoPorZero {
if (b == 0) throw new divisaoPorZero();
return a/b;
}
Calculadora Distribuída:
Implementação da Interface
public static void main(String[] args) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new
SecurityManager());
}
try {
String name = "Calculadora";
Calculadora calc = new CalculadoraImpl();
Calculadora stub = (Calculadora)UnicastRemoteObject.exportObject(calc,0);
Registry registry = LocateRegistry.getRegistry();
registry.rebind(name, stub);
System.out.println("Calculadora registrada!");
} catch (Exception e) {
System.err.println("Ocorreu excecao: ");
e.printStackTrace();
}
}
}
Calculadora Distribuída:
Implementação da Interface
Declarando a interface remota sendo
implementada:
public class CalculadoraImpl implements Calculadora
Podemos
criar objetos remotos da classe
CalculadoraImpl
Alguns dos seus métodos, entretanto, só
podem ser invocados localmente
Construtor e método main
Calculadora Distribuída:
Implementação da Interface
Definindo o construtor para o objeto
remoto
public CalculadoraImpl() {
super();
}
Em
nosso caso, apenas invoca construtor da
classe ancestral
Apesar de não ser necessário, foi adicionado por
questões de clareza de código
Calculadora Distribuída:
Implementação da Interface
Provendo implementações para cada método
remoto
Classe
provê implementações para todos os
métodos declarados na interface
som, sub, mul, div
Passagem de parâmetros em Java segue as
seguintes regras
Objetos
remotos passados por referência
Objetos locais passados por cópia
Todos os campos, exceto declarados estáticos ou
transientes
Desde que serializáveis e classes acessíveis (por
exemplo, via servidor web)
Calculadora Distribuída:
Implementação da Interface
Implementação do método main
Primeira
tarefa: instalar o gerente de
segurança
Protege o acesso aos recursos do sistema
Determina, por exemplo, se código pode ter acesso ao
sistema local de arquivos ou realizar qualquer outra
ação privilegiada
Receita de bolo:
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
Calculadora Distribuída:
Implementação da Interface
Implementação do método main
Segunda
tarefa: tornar os objetos remotos
disponíveis para o cliente
Instanciar objeto
Exportar objeto, com
UnicastRemoteObject.exportObject, de forma
que ele possa receber chamadas remotas:
Calculadora stub = (Calculadora)UnicastRemoteObject.exportObject(calc,0);
Segundo parâmetro indica número da porta TCP a
ser ouvida
Zero indica porta anônima
Porta real escolhida por SO ou RMI
Calculadora Distribuída:
Implementação da Interface
Implementação do método main
Método exportObject retorna stub para
objeto remoto exportado
Observe que tipo do stub deve ser da interface, e
não da implementação
Antes
do cliente invocar um objeto em um
objeto remoto, deve primeiro obter referência
para objeto remoto
Registro faz esse papel
Serviço de nomes, que fornece uma referência
para objeto remoto, dado um nome
Calculadora Distribuída:
Implementação da Interface
Servidor registra nome no serviço de
nomes
String name = "Calculadora";
Registry registry = LocateRegistry.getRegistry();
registry.rebind(name, stub);
Rebind faz chamada remota para registro
localizado na máquina do servidor
Como qualquer chamada remota, pode
retornar exceção, que deve ser tratada
Bloco try/catch faz tratamento
Calculadora Distribuída:
Implementando o Cliente
package exemplo;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class CalculadoraClnt {
public static void main(String args[]) {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
Calculadora Distribuída:
Implementando o Cliente
try {
String name = "Calculadora";
Registry registry = LocateRegistry.getRegistry(args[0]);
Calculadora calc = (Calculadora) registry.lookup(name);
System.out.println("2 + 2 = " + calc.som(2,2));
} catch (Exception e) {
System.err.println("Calculadora exception:");
e.printStackTrace();
}
}
}
Calculadora Distribuída:
Implementando o Cliente
Assim como servidor, começamos declarando gerente
de segurança
Necessário se cliente fizer download de código do servidor a
partir do servidor web
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
Próximo passo: localizar referência para objeto remoto
String name = "Calculadora";
Registry registry = LocateRegistry.getRegistry(args[0]);
Calculadora calc = (Calculadora) registry.lookup(name);
Calculadora Distribuída:
Implementando o Cliente
Passo final: usar as funcionalidades do objeto
remoto, através de seus métodos, da mesma
forma que usaríamos as funcionalidades de um
objeto local
System.out.println("2 + 2 = " + calc.som(2,2));
Calculadora Distribuída:
Compilação e Execução
Para compilar:
Compilar
com javac *.java
Criar arquivo jar com classes relacionadas ao
servidor: jar cvf server.jar Calculadora.class
CalculadoraImpl.class divisaoPorZero.class
Caso código do servidor seja acessado
através de servidor web, disponibilizar arquivo
jar em pasta acessível via rede
Caso alguma classe do cliente seja acessada
pelo servidor, deve-se criar jar e disponibilizálo através da rede
Calculadora Distribuída:
Compilação e Execução
Antes de executar:
Criar
arquivo contendo políticas de segurança
Neste exemplo, daremos todas as
permissões de acesso:
grant {
permission java.security.AllPermission;
};
Calculadora Distribuída:
Compilação e Execução
Para executar:
Iniciar
rmiregistry (rmiregistry&)
Iniciar servidor: java -Djava.security.policy=f:\
calc\exemplo\secpolicy
-Djava.rmi.server.codebase=file:\f:calc\exempl
o\server.jar CalculadoraImpl
Iniciar cliente: java
-Djava.security.policy=f:\calc\exemplo\secpoli
cy CalculadoraClnt localhost
Resultado: 2 + 2 = 4.0
Próxima Aula...
Remote Procedure Call (cont.)
Questões
de Implementação
Problemas