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:
-
leitura das horas;
- modificação das horas.
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:
-
Envia uma mensagem por segundo.
- 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.