Sistemas Distribuídos 4º Ano MIEIC/5º Ano MIEEC
Trabalho Prático nº 1: Serviço de Tempo com sockets
UDP em Java


1  Introdução

1.1  Objectivo

Este trabalho prático tem por objectivo principal a consolidação dos conceitos fundamentais requeridos para a programação de aplicações distribuídas directamente sobre UDP.

Pretende-se também que ganhem alguma familiaridade com a interface de programação baseada em sockets, a qual foi adoptada por quase todos os sistemas operativos disponíveis no mercado.

1.2  Método

Há um provérbio que diz (cito de memória):
Ouço, esqueço. Vejo, memorizo. Faço, aprendo.
Assim, espero que cada um de vocês (ou no máximo, em pares) tente resolver por si só o problema proposto neste TP. Obviamente poderão discutir com os vossos colegas os problemas, bem como possíveis soluções. Também podem, e devem, consultar a documentação Java disponibilizada pela Sun.

1.3  Siga as instruções com rigor

Os enunciados deste TP são uma especificação do vosso trabalho. Como engenheiros, uma parte significativa do vosso trabalho requererá que sigam especificações, elaboradas por vocês ou por outros: uma solução para um problema errado não é correcta. Habituem-se a seguir as especificações dos problemas que têm que resolver. (No entanto, mantenham uma atitude crítica para detectar eventuais inconsistências ou erros.)

Neste TP é pedido que escrevam dois programas, um cliente e um servidor, usando, se assim o desejarem, uma classe que vos é fornecida. Cabe-vos definir e conceber as outras funções, bem como o seu agrupamento em ficheiros. No entanto, deverão criar uma Makefile que permita gerar os vossos programas usando dois simples comandos, a saber:
make DateClient, para gerar o cliente;
make DateServer, para gerar o servidor.
Apesar de ter tentado o meu melhor no que diz respeito à clareza e ao rigor deste guião, é inevitável que não tenha eliminado todas as ambiguidades. Assim, em caso de dúvida, não hesitem em enviar-me email.

2  A aplicação

Neste trabalho prático vão escrever uma aplicação cliente-servidor para determinar (e acertar) a hora.

A ideia é usar um processo servidor que ``tem'' um relógio e fornece a hora a processos clientes que pretendam saber a hora. A utilização dum único processo servidor permite que os diferentes clientes usem uma base de tempo comum.

De facto, embora cada computador tenha um relógio é muito provável que o valor dos relógios dos diferentes computadores dum sistema distribuído sejam distintos. Algumas razões para os múltiplos valores incluem: 1) os relógios foram inicializados com horas distintas, 2) as frequências reais dos relógios são diferentes das nominais, conduzindo a atrasos/avanços, 3) a pilha da motherboard está gasta e consequentemente, o relógio é reinicializado (em 1 de Janeiro de 1980, no caso dos PCs) cada vez que o computador é ligado.

Obs.- Em princípio, os computadores da FEUP executam uma aplicação de sincronização de relógios, que permite manter os relógios sincronizados com diferenças de poucos ms.

3  Protocolo de comunicação cliente-servidor

Numa aplicação cliente-servidor, o cliente envia pedidos ao servidor. Este último processa os pedidos, retornando os resultados, se alguns, aos clientes.

Numa aplicação baseada em sockets quer os pedidos quer os resultados são enviados em mensagens. A mensagem enviada pelo cliente deverá incluir o pedido em si bem como qualquer parâmetro. É responsabilidade do cliente construir a mensagem pedido. Por outro lado, o servidor terá que identificar o pedido e extrair qualquer parâmetro de cada mensagem que recebe dum cliente, e invocar a função que processa o pedido. Do mesmo modo, cabe ao servidor construir a mensagem de resposta, se alguma, possivelmente com os resultados do processamento do pedido. O cliente por sua vez terá que interpretar a mensagem resposta, se alguma.

O formato e o significado das mensagens trocadas entre o cliente e o servidor, bem como as regras que regulam a troca dessas mensagens constituem o protocolo de comunicação entre o cliente e o servidor.

Neste TP, o servidor deverá ser capaz de responder a 2 pedidos: Obs.- Não nos preocuparemos com problemas de controlo de acesso: numa aplicação a sério, não deveria ser possível que qualquer utilizador alterasse a hora. (Por exemplo, em Unix só o root tem permissões para alterar a hora do relógio local.)

O formato das mensagens pedido deverá ser:
``GETTIME''
para ler as horas;
``ADJTIME delta''
para acertar as horas, onde ``delta'' é uma string representando um inteiro com sinal que indica o número de segundos a somar à hora actual;
O formato para as mensagens resposta a qualquer destes pedidos deverá ser:
``data''
uma string com a data e hora, no formato que acharem apropriado.
Notem que todas as mensagens do protocolo especificado acima são strings legíveis, o que simplifica o debugging da aplicação. Outra vantagem é que, normalmente, não há necessidade de fazer conversão de formatos dos conteúdos das mensagens. No entanto, há também alguns problemas com este tipo de protocolos. Por exemplo, conduzem a mensagens mais longas. No caso da aplicação deste TP, atendendo a que há apenas 2 tipos de pedidos, bastar-nos-ia usar um bit, para indicar o tipo da mensagem (seria sensato usar mais bits, para o caso de se decidir acrescentar mais mensagens). Outro inconveniente é que o processamento de protocolos baseados em strings é mais elaborado. P.ex., ao fazer a desmultiplexação das mensagens, em vez de usar uma simples instrução switch tem-se que usar funções de comparação de strings.

A maioria dos protocolos da camada aplicação, p.ex. FTP e HTTP, usam protocolos baseados em strings. Pelo contrário, a generalidade dos protocolos de níveis mais baixos usam protocolos em que o tipo de mensagem é codificado em alguns bytes.

4  Comunicação com Sockets do Tipo DGRAM

Para implementar a aplicação acima descrita deverão desenvolver duas classes (DateClient) e (DateServer) usando a classe java.net.DatagramSocket.

IMPORTANTE: Sigam uma estratégia de desenvolvimento segura: implementem e testem a vossa solução incrementalmente.

A vossa aplicação poderá usar a classe:

 public class MyClock {
   static String getTime();
   static String adjTime(double adj);
 } 
      
que fornece os métodos getTime() e adjTime(), para lêr e acertar a hora, respectivamente, e que se encontra no ficheiro MyClock.java. Este ficheiro inclui ainda um método main(), o qual invoca os métodos acima e imprime a string por eles retornada.

Dica Compilem e executem a classe MyClock e analisem o formato da mensagem impressa: notem que esse formato satisfaz a especificação das mensagens resposta.

Servidor

O programa servidor deverá ser invocado da seguinte maneira:
java DateServer <port_number>
onde
<port_number> é o número do porto que o servidor deverá usar.
O programa servidor deverá imprimir mensagens na consola indicando as acções executadas, nomeadamente os pedidos recebidos e a sua fonte (endereço IP e número do porto do cliente), bem como as respostas enviadas.

Dica Usem o método String.split() para fazer o parsing dos pedidos recebidos do cliente.

Cliente

O programa cliente deverá ser invocado da seguinte maneira:
java DateClient <host_name> <port_number>
onde
<host_name> é o nome DNS do computador onde executa o servidor;
<port_number> é o número do porto do servidor.
O processo cliente deverá criar um socket e executar um ciclo infinito no qual:
  1. Envia uma mensagem por segundo.
  2. Por cada 3 mensagens GETTIME deve enviar uma mensagem ADJTIME com um valor à vossa escolha.
Após submeter um pedido, o cliente fica à espera até receber uma resposta.

O programa cliente deverá imprimir mensagens na consola indicando as acções executadas, nomeadamente os pedidos enviados ao servidor bem como as respostas respectivas.

Dica Usem o método Thread.sleep() para bloquear o cliente por um segundo entre pedidos. (O método main() da classe MyClock também espera um segundo entre invocações dos métodos dessa classe: analise o seu código.)

Para pensar:

O que acontece se houver perda de mensagens, ou se o servidor não estiver a funcionar? Como poderiam tornar o vosso cliente robusto contra este tipo de eventos? Se estiverem interessados e tiverem tempo, tentem implementar uma solução.
This document was translated from LATEX by HEVEA.