• Nenhum resultado encontrado

Arquitetura Voltadas para Interoperabilidade

No documento 14785589987745587 (páginas 44-65)

Exercícios de fixação

Questão 1 - E

Justificativa: A sigla RTI significa Infraestrutura de tempo de execução, e cuida do gerenciamento das Federates, Federation e Federation Execution, entre outros elementos.

Questão 2 - E

Justificativa: Quem criou o HLA foi o Defense Modeling and Simulation Office (DMSO).

Questão 3 - C

Justificativa: Os componentes responsáveis pelas funções citadas nestas opções são:

– Gestão de declarações, que controla o modelo de publicação e assinatura

para troca de informações;

– Gestão de dados distribuídos, com a transmissão eficiente de dados

entre Federates;

Gestão de tempo, o qual coordena a linha de tempo de cada Federate

dentro do eixo de tempo do Federation, garantindo a preservação de causa e ordenação.

– Gestão de objetos, controlando todo o ciclo de vida e troca de

mensagens entre estes objetos;

– Gestão de Federation, que controla as atividades de cada Federation durante a execução.

Questão 4 - A

Justificativa: Uma aplicação compatível com o ambiente HLA é denominada Federate.

Questão 5 - E

Justificativa: Inicialmente a HLA foi normatizada pelo IEEE Standard 1516-2000. Questão 6 - E

Justificativa: A única opção que não trata de uma mensageria comercial é o QueueSender. Este é, na verdade, o componente Java necessário para enviar uma mensagem no modelo de fila sem uso de EJBs.

Questão 7 - D

Justificativa: No modelo de tópico é necessário um objeto ouvinte (MessageListener) para avisar que há nova mensagem no canal, de forma que os assinantes possam recebê-la.

Questão 8 - B

Justificativa: O uso de mensagerias é indicado em todos estes casos, menos quando há necessidade de bloquear o cliente, isso porque o funcionamento é justamente o oposto, sem bloqueio do cliente, o que viabiliza o comportamento assíncrono.

Questão 9 - A

Justificativa: O middleware para acesso a mensagerias é denominado MOM, ou Message Oriented Middleware. As opções RPC e RMI referem-se a sistemas de processamento distribuído, enquanto JDBC é o middleware para acesso a banco de dados do Java, e o EJB um componente corporativo da plataforma JEE. Questão 10 - C

Justificativa: O componente responsável pela recepção das mensagens é o Message Driven Bean, definido pela anotação @MessageDriven, e que precisa implementar a interface MessageListener.

Introdução

Uma evolução natural da programação foi a utilização de processamento paralelo para a resolução de problemas complexos.

A distribuição de processamento também é utilizada com tal finalidade, ou em situações nas quais os participantes de uma transação não se encontram fisicamente no mesmo local.

Esta aula visa elucidar conceitos como processamento paralelo e distribuído, além de descrever tecnologias de grande aceitação na implementação de sistemas distribuídos, como RPC e RMI.

Objetivo:

1. Compreender o processamento distribuído e uso do RPC; 2. Conhecer a tecnologia Java RMI.

Conteúdo

Processamento paralelo

1945

Já em 1945, nos trabalhos de Von Neumann, as arquiteturas de processamento paralelo eram apresentadas como uma solução para aumento do poder de processamento.

As técnicas de processamento paralelo sempre visaram ao melhor aproveitamento do tempo de CPU, particularmente quando ocorriam “demorados” procedimentos de Entrada e Saída.

1950 a 1970

De 1950 a 1970 era comum a utilização de computadores monoprocessados. Havia uma busca por processadores cada vez mais velozes, porém existiam barreiras físicas para essa velocidade, assim, a solução mais viável para a otimização do tempo consistiria posteriormente em trabalhar com máquinas multiprocessadas.

A miniaturização proporcionada pela evolução da tecnologia de transistores permitiu que até mesmo bilhões deles fossem integrados em um chip, viabilizando a definição de arquiteturas de processadores com mais unidades funcionais e memória cache.

Com isso, temos hoje processadores com vários núcleos, com grande poder de processamento, mais bem explorados pelas técnicas de programação paralela com multitarefa.

Em linguagem Java, uma tarefa independente pode ser definida pela extensão da classe Thread. Outra forma seria a implementação da interface Runnable, o que não elimina a necessidade da chamada inicial com uma classe Thread. A tarefa que deverá ser executada continuamente em paralelo é definida no

método run, e quando há necessidade de sincronização utiliza-se a palavra- chave synchronized.

Processamento distribuído

A distribuição de processamento também pode ocorrer ao longo de uma rede, com diferentes processos sendo executados em máquinas remotas, segundo protocolos específicos de comunicação.

O termo DCE (Distributed Computing Environment) é comumente utilizado para definir esse tipo de ambiente, onde vários componentes de software, como serviços de diretórios, gestores de segurança, sistemas de objetos distribuídos, entre vários outros, trabalham em conjunto para a construção de complexos sistemas corporativos.

Dentro de uma rede TCP-IP, a definição de um serviço distribuído de forma mais simples envolve a construção de um servidor, normalmente trabalhando com paralelismo, que seja capaz de escutar uma porta específica destinada ao serviço oferecido, e clientes capazes de se comunicar com esse servidor segundo um protocolo previamente estabelecido.

Um código em linguagem Java de exemplo para a criação de um sistema cliente-servidor com uso de Socket.

Embora qualquer sistema cliente-servidor possa atuar dessa forma, algumas arquiteturas próprias foram definidas para a formalização dos serviços distribuídos, como o RPC e o RMI.

(imagem representativa de um código em linguagem Java)

RPC (Remote Procedure Call)

A chamada remota de procedimento (RPC) trata de um modelo de comunicação entre processos que viabiliza a chamada de um procedimento em outro espaço de endereçamento, normalmente em outro computador da rede, sem que o programador tenha que se preocupar com detalhes dessa interação remota, assemelhando-se a chamadas locais em termos de código.

Com isso, o uso de RPC simplifica a criação de sistemas distribuídos deixando a comunicação transparente para o programador.

Essa é uma ideia antiga, datando de 1976, quando foi descrita na RFC 707. Foi utilizada de maneira comercial inicialmente pela Xerox, em 1981, sendo a primeira implementação popular efetuada para UNIX com o Sun RPC, usado como base para o NFS (Network File System).

Várias extensões da comunicação remota para ambientes de objetos distribuídos, como CORBA e DCOM, são baseadas em diferentes implementações do RPC. As ferramentas para criação de aplicativos RPC cuidam da geração dos stubs para garantir essa transparência.

A ideia fundamental é a de que o servidor exporta apenas a interface de procedimentos e funções, da mesma forma que ocorreria com uma API ou biblioteca.

O programa cliente faz a chamada ao procedimento remoto, com a passagem dos parâmetros necessários, e recebe a resposta, como se estivesse chamando um simples método local.

O par de stubs faz a transformação de chamadas e respostas nas mensagens necessárias para a comunicação em rede. Em termos do servidor, esse elemento responsável pela interceptação das chamadas é comumente denominado skeleton, e deve receber a chamada, ativar o componente de software responsável pelo processamento do pedido, e retornar com a resposta solicitada.

Com todas essas características, o único vínculo real entre o código do cliente e o do servidor é a interface de exposição de serviços, a qual segue uma sintaxe bastante simples.

Um exemplo de sistema com uso de RPC na sintaxe C, bem como a interface de exposição dos serviços:

/* addsub.x : definição da interface */ #define PROGRAM_NUMBER 12345678

#define VERSION_NUMBER 1

/* tipo de dado que será passado aos procedimentos remotos */

struct operands

{

int x;

};

/* Definição da interface que será oferecida aos clientes */

program ADDSUB_PROG

{

version ADDSUB_VERSION {

int ADD (operands) = 1;

int SUB (operands) = 2;

}

= VERSION_NUMBER; }

= PROGRAM_NUMBER;

Com o uso do utilitário rpcgen são gerados vários arquivos a partir desse arquivo de interface, compreendendo toda a parte de comunicação e oferta de serviços, o que deixará para o programador a simples tarefa de implementar as regras de negócios do aplicativo, sem se desgastar com a comunicação e

distribuição.

/* Arquivo server.c: um servidor RPC simples */ #include <stdio.h>

#include "addsub.h"

/* implementação da função add */

int * add_1_svc (operands *argp, struct svc_req *rqstp) {

static int result;

printf ("Recebi chamado: add %d %d\n", argp->x, argp->y);

result = argp->x + argp->y;

return (&result); }

int * sub_1_svc (operands *argp, struct svc_req *rqstp) {

static int result;

printf ("Recebi chamado: sub %d %d\n", argp->x, argp->y);

result = argp->x - argp->y;

return (&result); }

O código do cliente é um pouco mais complexo que o do servidor, mas é fácil observar como a chamada remota assemelha-se a uma simples chamada de função local.

/* Arquivo client.c: um cliente RPC simples */

#include <stdio.h> #include "addsub.h"

/* função que chama a RPC add_1 */ int add (CLIENT *clnt, int x, int y) {

operands ops;

int *result;

/* junta os parâmetros em um struct */ ops.x = x;

ops.y = y;

/* chama a função remota */ result = add_1 (&ops,clnt);

if (result == NULL)

{

printf ("Problemas ao chamar a função remota\n");

exit (1); } return (*result); }

int main( int argc, char *argv[]) {

CLIENT *clnt;

int x,y;

/* verifica se o cliente foi chamado corretamente */ if (argc!=4)

{

fprintf (stderr,"Usage: %s hostname num1 num2\n",argv[0]);

exit (1);

}

/* cria uma struct CLIENT que referencia uma interface RPC */ clnt = clnt_create (argv[1], ADDSUB_PROG, ADDSUB_VERSION, "udp");

/* verifica se a referência foi criada */ if (clnt == (CLIENT *) NULL) { clnt_pcreateerror (argv[1]); exit(1); }

/* obtém os dois inteiros que serão passados via RPC */ x = atoi (argv[2]);

y = atoi (argv[3]);

/* executa um procedimento remoto */

printf ("%d + %d = %d\n", x, y, add (clnt,x,y));

return (0); }

(imagens representativas de Interface para definição dos serviços (IDL).)

RM(Remote Method Invocation)

A tecnologia RMI pode ser considerada como a versão orientada a objetos do RPC, disponível para a linguagem Java.

Nesse modelo o que temos é um objeto hospedado e executado em determinado servidor, registrado via RMI Registry, e que disponibiliza métodos para acesso remoto.

A arquitetura de comunicação do RMI pode ser observada no desenho seguinte, onde pode ser vista a presença dos stubs nos clientes e do skeleton no servidor.

(imagem representativa da tecnologia RMI)

O passo inicial para o desenvolvimento de um sistema com uso de RMI é a definição da interface remota, o que equivaleria à definição da IDL utilizada no RPC, porém restrita ao universo Java.

Essa interface deverá ser descendente da interface Remote e cada método dela deverá considerar a ocorrência da exceção RemoteException, como pode ser observado no exemplo seguinte:

Criada a interface, deve ser definido um objeto servidor que a implementa, criando assim os métodos do serviço.

Esse objeto também deve ser descendente de UnicastRemoteObject.

Um objeto da classe CalcRemote deve ser instanciado e registrado pelo programa servidor, ficando disponível para os clientes através da escuta efetuada pelo RMI Registry.

Com relação ao cliente, este deverá localizar o objeto servidor através do protocolo gerenciado pelo RMI Registry, efetuando a chamada aos métodos remotos, segundo o que foi definido em ICalcRemote.

O uso de RMI permite a definição de um DCE de grande simplicidade de uso para a linguagem Java, permitindo a passagem de informações através de objetos serializáveis mais complexos, segundo um padrão Proxy, diminuindo muito o esforço de programação.

No entanto, quando são tratados os sistemas corporativos, vários requisitos, como transações, pooling e autenticação, podem não ser oferecidos de forma simples pelo RMI. Para satisfazer a esse tipo de necessidade são utilizados ambientes de objetos distribuídos.

Marshalling e Unmarshalling

Um conceito comum em termos de programação orientada a objetos é a serialização de objetos.

A serialização é a transformação de dados em geral, que estejam em memória, para um formato adequado em array de bytes, pronto para armazenagem ou transferência do mesmo.

Em outro momento o processo inverso (desserialização) pode ser efetuado, partindo do array de bytes e montando a estrutura novamente em memória, claro que ocupando locais diferentes da mesma.

Em termos de comunicação remota, um conceito similar é o de Marshalling e Unmarshalling, pois trata da transformação dos dados estruturados segundo uma determinada tecnologia, como Java ou C#, em formato compatível com as mensagens que são trafegadas entre os stubs (Marshalling), bem como o processo inverso, para a recuperação dos dados a partir da mensagem (Unmarshalling), lembrando que nas duas pontas as linguagens podem ser distintas.

Serviços de nomes e diretórios

A chamada remota de procedimento (RPC) trata de um modelo de comunicação entre processos que viabiliza a chamada de um procedimento em outro espaço de endereçamento, normalmente em outro computador da rede, sem que o programador tenha que se preocupar com detalhes dessa interação remota, assemelhando-se a chamadas locais em termos de código.

 Associam nomes a recursos computacionais em rede;

 Funcionam como “diretórios” compartilhados;

 Envolvem funções de localização e registro de elementos;

 Permitem armazenar objetos, certificados digitais e outros elementos

serializáveis.

Amplamente utilizados pelas instituições bancárias, DAP (Directory Access Protocol) e LDAP (Lightweight Directory Access Protocol) são exemplos desse tipo de serviço. No caso da tecnologia Java, as ações de registro e localização são feitas pelo JNDI (Java Naming and Directory Interface), o qual apresenta

uma interface única entre os diversos serviços de diretório, gerenciando inclusive o acesso a recursos como RMI, CORBA, DAP, LDAP e JEE.

Atividade proposta

Implemente um serviço RMI que receba o valor de dois catetos de um triângulo retângulo e retorne o valor da hipotenusa.

Parâmetros de entrada: double cateto1, double cateto2 Retorno: double

Cálculo: hipotenusa = Math.sqrt(Math.pow(cateto1,2)+Math.pow(cateto2,2))

Referências

Silva, F. Sistemas Distribuídos: Conceitos e Projeto RPC e RMI, UFMA, 2013 http://www.deinf.ufma.br/~fssilva/graduacao/sd/aulas/rpc_rmi.pdf Grosso, W. Java RMI (Java Series), O’Reilly, 2001.

Exercícios de fixação

Questão 1

Quando trabalhamos com processamento paralelo, um problema comum é a utilização de recursos compartilhados que podem ser lidos ou escritos de forma errônea devido à preempção. Para resolver isso deve ocorrer um sequenciamento no acesso ao recurso, o que é obtido no Java com o uso da palavra reservada: a) static b) volatile c) synchronized d) abstract e) final Questão 2

Uma classe ServerSocket deve escutar uma porta especificada e aceitar conexões solicitadas pelos clientes, repassando as mesmas para objetos Socket locais, o que define o circuito virtual entre cliente e servidor. Qual o método utilizado para aceitar uma conexão?

a) start b) accept c) getInputStream d) getOutputStream e) close Questão 3

A utilização de RPC viabiliza a construção de sistemas de processamento distribuído com um formato de comunicação transparente para o programador. Quem permite esta transparência são os _______________ definidos para o padrão Proxy.

a) senders b) idles c) clients

d) stubs e) publishers

Questão 4

Na arquitetura do RPC, o elemento responsável por tratar as chamadas no servidor é denominado: a) IDL b) stub c) skeleton d) Socket e) ServerSocket Questão 5

O elemento na arquitetura do RPC que permite a geração automática de todo o aparato de comunicação em rede, de forma automatizada, por ferramentas como o rpcgen é: a) IDL b) stub c) skeleton d) Socket e) ServerSocket Questão 6

Em sistemas de processamento distribuído ocorre a necessidade de registrar e localizar componentes disponibilizados remotamente. O componente de software responsável por executar esta função seria:

a) Interface de Descrição de Serviços b) Serviço de Nomes e Diretórios c) Temporizador

d) Protocolo de Comunicação e) Gerenciador do Banco de Dados

Questão 7

A transformação dos dados estruturados segundo uma determinada tecnologia, como Java ou C#, em formato compatível com as mensagens que são trafegadas entre os stubs é denominada:

a) serialização b) unmarshalling c) marshalling d) de-serialização e) vetorização Questão 8

Em termos de RMI a descrição dos serviços é feita na própria linguagem Java através de uma interface descendente de:

a) Remote b) Runnable c) MessageListener d) Serializable e) CommandListener Questão 9

Considere as afirmativas abaixo:

I – Os métodos expostos pela interface remota do RMI devem considerar a ocorrência da exceção RemoteException.

II – Criada a interface, deve ser definido uma classe que implementa a mesma e seja descendente de UnicastRemoteObject.

III – Os passos I e II são necessários e suficientes para a criação de um servidor RMI.

Quais as afirmativas corretas? a) Todas estão corretas

b) Apenas a I está correta c) Apenas a II está correta

e) Nenhuma está correta Questão 10

No ambiente Java os serviços de nomes e diretórios são acessados através de: a) DAP

b) LDAP c) DNS d) JEE e) JNDI

No documento 14785589987745587 (páginas 44-65)