Desenvolvimento - Java

Exemplo prático do uso de RMI em sistemas distribuídos: Serviço de Criptografia

O objetivo deste artigo é explorar um exemplo de programa que utiliza a estrutura RMI (Invocação de Métodos Remotos). Para isso, será abordado um exemplo prático distribuído: o serviço de criptografia e descriptografia em RMI na linguagem Java.

por Edílson da Costa do Nascimento



Edílson da Costa do Nascimento, Ighor Amaral Souza, Rodrigo Barroso Gadelha1

Universidade Federal do Pará (UFPA)

Instituto de Ciencias Exatas e Naturais - Faculdade de Computação

Curso de Especialização em Redes de Computadores

Av. Augusto Meira, 01 – 66.075-110 –Belém – PA – Brazil

Abstract. The aim of this paper is to explore a sample program that uses the structure of RMI (Remote Method Invocation). This will address a practical example distributed: the service encryption and decryption in RMI in Java.

Resumo. O objetivo deste artigo é explorar um exemplo de programa que utiliza a estrutura RMI (Invocação de Métodos Remotos). Para isso, será abordado um exemplo prático distribuído: o serviço de criptografia e descriptografia em RMI na linguagem Java.

Palavra-chave: Java, RMI, criptografia.

1-Introdução

Sistemas distribuídos em linguagem Java podem ser implementados utilizando-se diversas estruturas de comunicação entre processos, no entanto, as estruturas mais usadas são sockets e o RMI. Um socket, por definição, é um canal de comunicação entre processos que estabelece uma conexão entre eles na forma de cliente-servidor. Por meio de sockets, os computadores podem trocar informações através de uma rede. Um socket deve ser definido, basicamente, através das seguintes informações: endereço IP do servidor, porta onde se encontra o serviço solicitado no servidor, endereço IP do cliente, porta através da qual o cliente solicita o serviço.

Já RMI tem como objetivo, permitir aos programadores o desenvolvimento de aplicações distribuídas em Java com a mesma sintática e semântica usada em programas não distribuídos. Para isso, é necessário fazer com que os programas Java que rodam em uma JVM (máquina virtual) tenham acesso a programas em máquinas virtuais distribuídas, que no caso do RMI é conhecido como “invocação de métodos remotos”.

Este artigo preocupa-se com aplicações distribuídas em RMI, e usa como exemplo a aplicação em criptografia. No Capítulo 2, será abordada a aplicação da Criptografia. No Capítulo 3, definição da interface remota. No Capítulo 4, implementando a interface remota. No Capítulo 5, definição do servidor. No Capítulo 6, definição do cliente. No Capítulo 7, compilando e executando o servidor e cliente. E por fim, no Capítulo 8 têm-se as conclusões do artigo.

2- Aplicação da Criptografia

A aplicação de criptografia esta relacionada a segurança da informação, e neste caso trata-se de um programa cliente-servidor no qual o cliente quer criptografar uma mensagem. A mensagem é enviada para o servidor, o que criptografa a mensagem e devolve-a criptografada. O inverso também ocorre, o cliente envia uma mensagem criptografada e o servidor devolve descriptografada.

Imagine que uma empresa quer transmitir dados por email, mas esta preocupada com a possibilidade de seus emails estarem sendo rastreados. Todos os seus dados são transmitidos como texto e/ou números. Eles pedem para você escrever um programa que criptografará os dados para que possam ser transmitidos com mais segurança. O aplicativo de ler uma cadeia de caracteres digitados pelo usuário em um diálogo de entrada e criptografá-lo. O mesmo programa deverá decifrá-lo para formar o texto original. Aqui por simplicidade, usaremos a criptografia de chave simétrica com cifra de substituição, que substitui um símbolo por outro.

2.1 Criptografia usando RMI

Quando se desenvolve uma aplicação em Java RMI, alguns elementos básicos devem ser criados, tais como:

· Uma interface que disponibilize os métodos no servidor.

· Uma classe que fique localizada na JVM (Java Virtual Machine) do servidor e que implemente os métodos definidos na interface.

· Classes que implementem o protocolo de comunicação (Skel e Stub)3 e que sejam responsáveis por fazer com que a chamada de um método no cliente seja passada ao servidor de maneira transparente, assim como fazer com que o servidor responda de maneira conveniente a essa chamada, passando de volta ao cliente o valor de retorno. Um programa cliente que invoque os métodos remotos do servidor.

· Um serviço de nomes (rmiregistry) responsável por informar ao cliente onde está o servidor e que relacione corretamente a implementação deste ao stub do cliente.

Depois compilar e executar o servidor e o cliente.

Foi definida uma interface, a interface de Criptografia, a classe que implementa essa interface, a classe CriptografiaImpl, a classe ClienteCriptografia e a classe ServidorCriptografia

As classes Skel e Stub não precisam ser programadas manualmente, pois são geradas automaticamente por uma ferramenta própria do SDK (rmic). A partir da versão 1.2 de SDK, a classe Skel não é mais necessária, pois java já a implementa.

3. Definindo a interface Remota

A interface remota descreve os métodos remotos que o cliente utilizará para interagir com o objeto servidor remoto por RMI. Para criar uma interface remota, defina uma interface que estende a interface Remote (pacote java.rmi).

Sempre que computadores se comunicam através de uma rede, há o risco de ocorrerem problemas de comunicação. Por exemplo, um computador servidor poderia ter um mau funcionamento, um recurso de rede poderia não responder, etc. Se um problema de comunicação ocorre durante uma chamada de método remoto, um método remoto dispara uma RemoteException (um tipo de exceção verificada).

Cada método em uma interface Remote deve ter uma cláusula throws para indicar a possibilidade de uma RemoteException.

A interface Criptografia contem dois métodos, o criptografar e o descriptografar, que serão implementados pela classe CriptografiaImpl.

Figura 1: interface Criptografia.

4. Implementando a interface remota.

A seguir, a classe CriptografiaImpl implementa a classe remota Criptografia.

Existem dois métodos que implementam a interface definida e que possuem as seguintes funcionalidades:

A linha 2 inicia a declaração da classe CriptografiaImpl, que contem os métodos.

· criptografar ( String a ): A linha 9 inicia a declaração do método usado para que o servidor criptografe uma entrada de texto claro emitida pelo cliente, e a devolva ao cliente em texto cifrado. Esse método usa a criptografia simétrica com cifra de substituição de caracter, que substitui cada caracter por outro. A linha 11, cria um vetor de char, sem definir o seu tamanho e cria uma variável char auxiliar. A linha 17, obtém a cadeia de caracteres e a coloca em um vetor de char com o mesmo tamanho da cadeia, separando cada caracter.

A instrução for percorre o vetor de char procurando por um caracter especifico e quando o encontra o substitui. Ao final, o método retorna a saída na variável output.

· descriptografar ( String a ): A linha 53 inicia a declaração do método usado para que o servidor descriptografe uma entrada de texto cifrada emitida pelo cliente, e a devolva ao cliente em texto legível. Esse método usa a criptografia simétrica com cifra de substituição de caracter, que substitui cada caracter por outro. A linha 55, cria um vetor de char, sem definir o seu tamanho e cria uma variável char auxiliar. A linha 61, obtém a cadeia de caracteres e a coloca em um vetor de char com o mesmo tamanho da cadeia, separando cada caracter.

A instrução for percorre o vetor de char procurando por um caracter especifico e quando o encontra o substitui. Ao final, o método retorna a saída na variável output.

Figura 2: classe CriptografiaImpl, que implementa Criptografia, parte 1.

Figura 3: classe CriptografiaImpl, que implementa Criptografia, parte 2.

5. Definindo o Servidor

A linha 12, cria o objeto servidor do tipo CriptografiaImpl. Quando o construtor executa, ele exporta o objeto para que o objeto possa começar a ouvir as solicitações de clientes. Objetos remotos utilizam o host e a porta para localizar o rmiregistry a fim de poderem se registrar como serviços remotos. Os clientes utilizam o host e a porta para localizar um serviço.

A linha 13 define o nome do objeto servidor que será utilizado por clientes para tentar sua conexão. O nome é normalmente da forma //host:porta/nomeDoObjetoRemoto. em que host representa o computador que está executando o registro para objetos remotos (este também será o

computador em que o objeto remoto executa), porta representa o número da porta onde o registro pode ser localizado no host e nomeDoObjetoRemoto é o nome que o cliente fornecerá ao tentar localizar o objeto remoto pelo registro.

O registro para objetos remotos é gerenciado pelo programa utilitário rmiregistry incluído no J2SDK. O número-padrão da porta para o rmiregistry é 1099.

Nesse programa, o nome de objeto remoto do servidor é //localhost/criptoService. Indicando que o rmiregistry está localizado no localhost (isto é, no mesmo computador) e que o nome que o cliente deve utilizar para localizar o serviço é criptoService.

A linha 13, chama o método static rebind da classe Naming (pacote java.rmi) para vincular (bind) o objeto remoto obj de ServidorCriptografia ao rmiregistry e atribuir o nome //localhost/criptoService ao objeto remoto.

Figura 4: class ServidorCriptografia.

6. Definindo o cliente

O próximo passo é definir o código do cliente que obterá os serviços do ServidorCriptografia.

Figura 5: class ClienteCriptografia, parte 1.

Figura 6: class ClienteCriptografia, parte 2.

Quando a classe ClienteCriptografia executa, ela faz uma pergunta sobre qual serviço quer realizar (criptografia ou descriptografia), o cliente escolhe, entra com o texto e a classe faz uma chamada de método remoto especifico para o servidor.

7. Compilando e executando o servidor e o cliente.

Agora que os pedaços estão no lugar, podemos construir e executar nosso aplicativo distribuído; isso requer vários passos. Primeiro, as classes devem ser compiladas utilizando javac, para produzir os .class.

Em seguida, a classe que implementa a interface (CriptografiaImpl) deve ser compilada utilizando o compilador rmic (um dos utilitários fornecidos com o J2SDK) para produzir uma classe stub. Um objeto da classe stub permite que o cliente invoque os métodos remotos do objeto servidor. O objeto stub recebe cada chamada de método remoto e o passa para o sistema Java RMI, o qual realiza as funções de rede que permitem que o cliente se conecte ao servidor e interaja com o objeto servidor remoto. A linha de comando deve ser executada no diretório em que estão os .class, produzidas pelo compilador javac,

rmic CriptografiaImpl

,gera o arquivo CriptografiaImpl_Stub.class. Agora, podemos testar nosso aplicativo de RMI. O próximo passo é iniciar o rmiregistry de modo que o objeto CriptografiaImpl possa se registrar sozinho no registro. Isso é feito a partir da janela de comando. A linha de comando:

rmiregistry

carrega o registro de RMI e o vincula (binds) à porta 1099 na máquina em que o comando é executado. A janela de linha de comando não mostrará nenhum texto em resposta a esse comando.

Para tornar o objeto servidor remoto disponível para receber as chamadas de método remoto, ele deve ser vinculado ao registro. Execute o aplicativo ServidorCriptografia da linha de comando como segue, a partir do diretório onde se encontra o .class:

java ServidorCriptografia

O programa ClienteCriptografia agora pode ser executado para se conectar com o ServidorCriptografia no host local com o comando

java ClienteCriptografia

A janela resultante é mostrada na Figura X. Quando o programa executa, o ClienteCriptografia conecta-se ao objeto servidor remoto, o usuário escolha qual o serviço, insere um texto, que é enviado ao servidor e retorna o texto criptografado.

Figura 7: saída.

Se o ServidorCriptografia está executando em uma máquina diferente do cliente, você pode especificar o endereço de IP ou nome de host do computador de servidor como um argumento de linha de comando ao executar o cliente. Por exemplo, para acessar um computador servidor com endereço IP 192.168.0.150, insira o comando

java ClienteCriptografia 192.168.0.150.

8. Considerações Finais.

Neste artigo foi apresentado um exemplo de aplicação usando Java RMI. A RMI é a implementação da RPC (Chamada de Procedimento Remoto) por Java para comunicação distribuída de um objeto Java com outro. Uma vez que um método (ou serviço) de um objeto Java é registrado como sendo remotamente acessível, um cliente pode “pesquisar” (“lookup”) esse serviço e receber uma referência que permita ao cliente utilizar esse serviço. Como com RPC, a ordenação (marshal) de dados é tratada também por RMI.

A RMI oferece transferência de objetos de tipos de dados complexos através do mecanismo de serialização de objeto. A RMI trata dos detalhes da rede que suporta comunicação entre clientes e objetos remotos e transferência de argumentos e valores de retorno entre objetos.

Basicamente, este é um exemplo simples que mostra um pouco da capacidade das aplicações usando Java RMI.

Referências

Coulouris, G.; Dollimore, J.; Kindberg, T (2007). “Sistemas Distribuídos - conceito e projeto”. Editora Bookman.

Harvey M. Deitel and Paul J. Deitel (2003). “Java: how to program”. Quarta edição, Editora Bookman.

Edílson da Costa do Nascimento

Edílson da Costa do Nascimento