Buscar

Tecnologia de Comunicação em Sistemas Distribuídos

Prévia do material em texto

Tecnologia de Comunicação em Sistemas Distribuídos
Java Socket e Java RMI
Java RMI
O Java RMI é uma interface de invocação remota da linguagem Java, do inglês Remote Method Invocation que permite que aplicações distribuídas executem chamadas remotas baseadas na Chamada Remota de Procedimento, do inglês RPC (acrônimo de Remote Procedure Call) em aplicações desenvolvidas em Java. Esta interface atua como middleware, que abstrai ao programador questões envolvendo diferenças em hardware, rede, entre outros aspectos que poderiam levar preocupações desnecessárias ao programador que deverá concentrar seu trabalho apenas na questão da programação.
O principal propósito do RMI é o mesmo do RPC: facilitar a programação de uma aplicação distribuída na medida que esconde do programador a maioria dos detalhes relacionados com a comunicação em ambiente distribuído. Através da utilização da arquitetura RMI, é possível que um objeto ativo em uma máquina virtual Java possa interagir com objetos de outras máquinas virtuais Java, independentemente da localização dessas máquinas virtuais. Esta API, fornece ferramentas para que seja possível ao programador desenvolver uma aplicação sem se preocupar com detalhes de comunicação entre os diversos possíveis elementos (hosts) de um sistema.
Esta interface se posiciona em uma camada do middleware que fica abaixo da camada de aplicação e acima das camadas de protocolo de comunicação; sistema operacional e hardware. O RMI abstrai ao programador as diferenças encontradas nas camadas inferiores. O programador não terá muita dificuldade em implementar um sistema com objetos distribuídos, pois o RMI possui como uma de suas vantagens a facilidade em se programar em distribuído, pois mantém uma semântica muito semelhante a programação que envolve objeto locais. A programação só não é idêntica à quando programamos com objetos locais, pois em sistemas distribuídos há questões de rede envolvida que vão fazer com que seja necessário o tratamento de exceções e execuções particulares.
Em resumo, os passos para construir uma aplicação simples que utiliza RMI são três. Inicialmente é necessário definir uma interface remota que descreve como o cliente e o servidor se comunicam um com o outro. Em seguida, é necessário criar o código do programa servidor que implementa a interface remota definida antes. Finalmente, deve-se criar o programa cliente que, utilizando uma referência da interface remota, invoca os métodos da implementação remota da interface definida antes. Obviamente, uma vez definida a interface remota, os programas cliente e servidor podem ser desenvolvidos em paralelo.
Vantagens:
Orientado a objetos
Quase transparente com relação à chamada local: sintática e semanticamente;
Mais legível (vs sockets);
Atendimento concorrente à vários clientes;
Uso de máquinas multiprocessadores / multicore;
Melhor atendimento de chamadas curtas;
Transferência automática de código (por classes);
Construção de interfaces usando a própria linguagem Java, sem a necessidade de uma linguagem separada para a descrição de interfaces.
Desvantagens:
Menos flexível (com relação a algoritmos e padrões de comunicação);
Menos eficiente (versus sockets);
Somente entre programas Java (deixa a programação restrita à linguagem Java);
Síncrono: espera execução do método;
Modelo de relacionamento cliente/servidor em nível de objetos;
Simples, único;
Um (1) servidor para vários clientes;
Criação (gerência) de servidores pelo servidor.
Java Socket
O socket é uma abstração que representa um ponto de comunicação em uma rede de computadores. A troca de informações entre máquinas diferentes, utiliza o conceito de socket, no qual um computador atua como servidor, abrindo o socket e ficando na escuta, a espera de mensagens ou pedidos de conexões. O outro computador assume o papel de cliente, enviando mensagens para o socket do servidor.
Existem dois modos de operação: orientado a conexão, baseado no protocolo TCP (Transport Control Protocol) e sem conexão, empregando o protocolo UDP (User Datagram Protocol). Para usar sockets orientados a conexão, antes do envio dos dados é necessário o estabelecimento de uma conexão entre o cliente e o servidor. A conexão deve ser terminada ao final da comunicação e os dados chegam na mesma ordem que foram enviados. Quando sockets sem conexão são empregados, a entrega não é garantida. Dados podem chegar em ordem diferente da que foram enviados. O modo usado depende das necessidades da aplicação. Via de regra, o uso de conexão implica em maior confiabilidade, porém com maior overhead.
Cada computador em uma rede TCP/IP possui endereço IP único. Portas representam conexões individuais com esse endereço. Quando o socket é criado, ele deve ser associado com uma porta específica, isto é, efetuar o seu binding. Para estabelecer uma conexão o cliente precisa conhecer o endereço IP da máquina onde o servidor executa e o número da porta que o servidor está escutando.
A comunicação em si é feita com o auxílio de classes tipo streams, que são classes do pacote java.io. Os clientes seguem sempre a mesma receita básica: cria um socket com conexão cliente e utiliza classes que implementam streams para efetuar a comunicação. Existem diversas opções para sockets clientes, tais como definir o timeout usado no protocolo de desconexão, timeout utilizado em operações de leitura, etc.
Um servidor pode receber várias requisições de conexão ao mesmo tempo e as requisições são processadas uma a uma. A fila de requisições ainda não atendidas é denominada pilha de escuta. O tamanho da fila de escuta indica quantas requisições de conexão simultâneas são mantidas. Assim, na construção acima, o primeiro parâmetro é o número da porta a ser escutada e o segundo parâmetro é o tamanho da pilha de escuta. O valor default é 50.
O método accept() é chamado para retirar requisições da fila. Ele bloqueia o processo até a chegada uma requisição, e após isso, retorna um socket conectado com o cliente. O objeto socket do servidor não é usado, um novo é criado para a transferência dos dados. O socket do servidor continua enfileirando pedidos de conexão. Finalmente, streams são usados para a troca de dados. Um servidor simples processa uma conexão de cada vez.
Entretanto, utilizando múltiplas threads, um servidor concorrente vai criar uma nova thread para cada conexão aberta e assim consegue processar várias conexões simultaneamente. Por exemplo, servidores web comerciais são todos concorrentes.
No caso de comunicação baseada em datagramas, a classe DatagramSocket é usada tanto por clientes como por servidores. O servidor deve especificar sua porta, e a omissão do parâmetro significa “use a próxima porta livre”. O cliente sempre utiliza a próxima.
A classe DatagramPacket é usada para enviar e receber dados. Ela contém informações para conexão e os próprios dados. Para receber dados de um socket datagrama, o método receive() bloqueia até a recepção dos dados.
O envio de uma string para um socket destinatário é feito através da montagem de um objeto DatagramPacket, o qual conterá a mensagem e o endereço destino. Seu envio através do método send() de objeto da classe DatagramSocket criado anteriormente pelo cliente.
Vantagens:
Mais eficiente;
Mais flexível (com relação a algoritmos e padrões de comunicação);
Aprendizado rápido;
API uniforme (sobre outras API sockets).
Desvantagens:
Menos legível;
Não orientado a objetos em termos de chamada, mas usa classes e objetos.
Principais diferenças entre os modelos Java RMI e Java Socket
Sockets basicamente transmitem dados em baixo nível entre programas remotos. Dessa forma, se o programa existente realiza a comunicação a partir de sockets, não importa em que idioma ele está escrito, desde que os formatos das mensagens correspondam. O Java RMI possui um nível alto, no qual permite que você execute um método de um programa remoto, aguardando o retorno como se fosse uma chamada de método local, no entanto,esta opção é realmente apenas para comunicação entre programas Java;
O Java RMI é uma API que serve para você fazer chamadas de métodos remotas. Por exemplo, você consegue executar um método em outro computador. Socket seria um ponto de conexão entre dois computadores, o IP e porta de um computador através de especificações TCP ou UDP;
O Java RMI é um protocolo usado pelo Java para comunicação entre processos (programas) diferentes.Socket é um ponto de comunicação entre processos através de uma rede de computadores, um conceito de baixo nível.
Definição de Modelo Cliente/Servidor
Interações em um sistema distribuído ocorrem, usualmente, através do modelo cliente-servidor. No modelo cliente-servidor, um sistema é estruturado em processos cooperantes que assumem papeis de clientes ou de servidores. Um processo assume o papel de servidor quando ele oferece serviços aos outros processos clientes. Um mesmo processo pode ora fazer papel de cliente, ora papel de servidor. Por exemplo, um processo servidor de nomes, pode receber uma requisição para resolução de um nome o qual ele não possa resolver. Nesse caso, o servidor, temporariamente, assume papel de cliente fazendo uma requisição para outro servidor de nomes. Servidores de tempo (NTP) também funcionam de forma hierárquica, onde alguns servidores sincronizam seus relógios, periodicamente, fazendo requisições a outros servidores.
A maneira mais simples de implementar um modelo cliente-servidor é através de um protocolo simples do tipo requisição/resposta (request/reply). Essas primitivas, por sua vez, podem ser implementadas através de operações de envio e recepção de mensagens existentes, por exemplo, na API socket.Nessa implementação de protocolo, um processo cliente, envia uma mensagem de requisição para um servidor requisitando algum serviço (fazOperação()). Essa operação bloqueia o processo cliente enquanto não é retornada uma mensagem de resposta. No outro ponto final da comunicação, o servidor já estava bloqueado aguardando alguma requisição de serviço (aguardaPedido()). Ao receber o pedido de requisição, o servidor se desbloqueia, extrai a mensagem, executa a operação pedida pelo cliente, e retorna uma mensagem para o cliente (enviaResposta()). Um exemplo tradicional de implementação de um protocolo requisição/resposta é o HTTP, usado em interações entre navegadores e servidor web.
Referências
ftp://ftp.inf.ufrgs.br/pub/geyer/PDP-CIC-ECP/slidesAlunos/SemestresAnteriores/ProvaP1-2013-1/j07-javaComunicacao-v4d1-mar2013.pdf 
http://www.romulosilvadeoliveira.eng.br/artigos/Romulo-Joni-Montez-Eri2002.pdf

Continue navegando