Escolar Documentos
Profissional Documentos
Cultura Documentos
Aula03 Programacao de Redes de Computadores em Java PDF
Aula03 Programacao de Redes de Computadores em Java PDF
RedesdeComputadores
emJava
RafaelSantos
Sumrio
1 Introduo 1
2 Programao Cliente-Servidor 1
2.1 Introduo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
2.2 Conceitos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
4 Clientes simples 8
4.1 Exemplo: Cliente de daytime . . . . . . . . . . . . . . . . . . . . . . 8
4.2 Exemplo: Cliente de echo . . . . . . . . . . . . . . . . . . . . . . . . 10
9 Mais informaes 58
Lista de Figuras
1 Algoritmo para leitura e processamento de uma string . . . . . . . . . . 5
2 Algoritmo para o servidor de strings . . . . . . . . . . . . . . . . . . . 5
3 Algoritmo integrado do cliente e servidor de strings . . . . . . . . . . . 6
4 Outro algoritmo integrado do cliente e servidores . . . . . . . . . . . . 7
5 Protocolo de comunicao entre o cliente e o servidor de daytime . . . 8
6 Protocolo de comunicao entre o cliente e o servidor de echo . . . . . 11
7 Protocolo de comunicao entre o cliente e o servidor de inverso de
strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Lista de Listagens
1 Cliente de daytime . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2 Cliente de echo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3 Servidor de strings invertidas . . . . . . . . . . . . . . . . . . . . . . . 13
4 A classe Livro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
5 Servidor de instncias da classe Livro . . . . . . . . . . . . . . . . . . 18
6 Cliente para o servidor de livros . . . . . . . . . . . . . . . . . . . . . 20
7 Servidor de nmeros aleatrios . . . . . . . . . . . . . . . . . . . . . . 21
8 Cliente de nmeros aleatrios . . . . . . . . . . . . . . . . . . . . . . . 24
9 Servidor de arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
10 Cliente de arquivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
11 Segunda verso do servidor de nmeros aleatrios . . . . . . . . . . . . 31
12 Segunda verso do cliente de nmeros aleatrios . . . . . . . . . . . . 34
13 Classe que representa um carro de corrida para simulao. . . . . . . . 35
14 Simulao usando instncias de CarroDeCorrida. . . . . . . . . . . . 36
15 Classe que representa um carro de corrida para simulao (herdando de
Thread). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
16 Simulao usando instncias de CarroDeCorridaIndependente. . . . 38
17 Classe que implementa o servio de nmeros aleatrios . . . . . . . . . 40
18 Terceira verso do servidor de nmeros aleatrios . . . . . . . . . . . . 41
19 O servidor de Jogo-da-Velha . . . . . . . . . . . . . . . . . . . . . . . 45
20 O servidor de clculo de integrais . . . . . . . . . . . . . . . . . . . . 52
21 Uma linha de execuo para o cliente de clculo de integrais . . . . . . 55
22 O cliente de clculo de integrais . . . . . . . . . . . . . . . . . . . . . 57
1 Introduo
Este documento ilustra os conceitos bsicos de programao cliente-servidor usando
Java, usando protocolos, clientes e servidores desenvolvidos pelo programador. Para
melhor compreenso dos tpicos, alguns clientes simples para servidores j existentes
sero demonstrados.
Para a compreenso dos exemplos deste documento, o leitor deve ter os seguintes co-
nhecimentos tcnicos:
Conhecer algoritmos e a implementao de diversas estruturas de controle em Java
(condicionais, estruturas de repetio);
Programao orientada a Objetos usando a linguagem Java. Em especial neces-
srio compreender os conceitos de encapsulamento e herana, mecanismo de ex-
cees e o uso de mtodos estticos;
Conhecer alguns dos mecanismos de entrada e sada em Java (streams);
Conhecer conceitos bsicos do funcionamento de um computador ligado em uma
rede.
2 Programao Cliente-Servidor
2.1 Introduo
Consideremos os seguintes cenrios:
5. Precisamos obter informaes que esto em algum outro computador (de forma
semelhante ao caso 2) mas no sabemos onde estas informaes esto localiza-
das. Sabemos, no entanto, que um outro computador contm um catlogo destas
informaes.
Para o exemplo 4 podemos considerar uma soluo cooperativa: se o problema a ser re-
solvido puder ser dividido em vrios subproblemas menores independentes, poderamos
usar vrios computadores diferentes para resolver cada um destes pequenos problemas.
Um computador seria o responsvel para separar o problema em subproblemas, en-
viar estes subproblemas para diversos outros computadores e integrar o resultado. Um
exemplo deste tipo de cenrio a anlise de dados de genoma e proteoma, onde usu-
rios cedem parte do tempo de seus computadores para execuo de uma tarefa global.
2.2 Conceitos
Alguns conceitos cuja compreenso se faz necessria so listados a seguir.
Servidor o computador que contm a aplicao que desejamos executar via remota.
Servio uma aplicao sendo executada no servidor. Para cada tipo de servio (apli-
cao) pode ser necessrio ter um tipo de cliente especfico, capaz de realizar a
comunicao da forma adequada. comum usar os termos servio e servidor
para designar a aplicao a ser executada (ex. servidor de FTP).
Cliente a aplicao remota que far a comunicao e interao com o servio/servidor.
Endereo a informao da localizao de um computador em uma rede local ou na
Internet. Podem ser usados como endereos o nmero IP (Internet Protocol) do
computador ou um nome que possa ser resolvido por um servidor DNS (Domain
Name System).
Porta um endereo local em um computador conectado a uma rede, identificado por
um nmero nico. Todos os dados originados ou destinados a um computador
na rede passam pela conexo (geralmente nica) daquele computador, identificada
pelo seu endereo. Como vrias aplicaes podem estar enviando e recebendo
dados, necessrio um segundo identificador para que o computador saiba que
dados devem ir para cada aplicao. Este segundo identificador a porta, associada
com um servio.
Porta Bem Conhecida uma porta cujo nmero menor que 1024, e que corresponde
a servios bem conhecidos. Alguns exemplos so as portas 7 (servio echo), 13
(servio daytime), 21 (servio ftp) e 80 (servio http). Usurios comuns (isto ,
sem privilgios de administrao) geralmente no podem usar nmeros de portas
bem conhecidas para instalar servios.
Protocolo o dilogo que ser travado entre cliente e servidor1 . Este dilogo muito
importante quando vamos criar clientes e servidores especficos, pois dados devem
ser enviados do cliente para o servidor em uma ordem e formatos predeterminados.
1O termo protocolo mais conhecido para designar a maneira pela qual os dados sero recebidos e enviados entre cliente
e servidor; alguns exemplos mais conhecidos so TCP (Transmission Control Protocol) e UDP (User Datagram Protocol).
Cliente
Incio
Abre conexo
L string
Processa a string
Fim
Servidor
Incio
Cria conexo
Envia string
Para descrevermos a aplicao como um todo usando diagramas similares aos de ati-
Cliente Servidor
Incio Incio
Cria conexo
Fim
Cria conexo
Incio
Cria conexo
Processa informaes
Fim
4 Clientes simples
Veremos nesta seo alguns clientes simples para servios existentes3 . Estes clientes
so totalmente funcionais, e servem para demonstrar o uso das classes para comunica-
o entre clientes e servidores.
Cliente Servidor
Incio Incio
Cria conexo
Fim
No sistema operacional Linux, o servio daytime pode ser acessado com o aplicativo
telnet, que deve receber como argumentos o nome do servidor e o nmero da porta,
separados por espao (por exemplo, telnet localhost 13). Ao invs de acessar o
servio desta forma, vamos escrever uma aplicao em Java que o faa para ns. A
aplicao mostrada na listagem 1.
Listagem 1: Cliente de daytime
1 package cap312;
2 import java.io.BufferedReader;
3 import java.io.IOException;
3 Osservios utilizados nesta seo so servios padro do sistema operacional Linux, desabilitados por default. Para
computadores executando o sistema operacional Red Hat, verifique os arquivos no diretrio /etc/xinetd.d para habilitao
dos servios.
4 import java.io.InputStreamReader;
5 import java.net.Socket;
6 import java.net.UnknownHostException;
7
8 /**
9 * Esta classe implementa um cliente simples para o servio daytime (porta 13).
10 * A classe simplesmente cria um socket para um servidor (no exemplo,
11 * localhost) usando aquela porta, obtm um BufferedReader (usando um
12 * InputStreamReader a partir do InputStream da conexo) e l uma linha do
13 * servidor.
14 */
15 public class ClienteDeDaytime
16 {
17 public static void main(String[] args)
18 {
19 String servidor = "localhost";
20 // Tentamos fazer a conexo e ler uma linha...
21 try
22 {
23 Socket conexo = new Socket(servidor,13);
24 // A partir do socket podemos obter um InputStream, a partir deste um
25 // InputStreamReader e partir deste, um BufferedReader.
26 BufferedReader br =
27 new BufferedReader(
28 new InputStreamReader(conexo.getInputStream()));
29 String linha = br.readLine();
30 System.out.println("Agora so "+linha+" no servidor "+servidor);
31 // Fechamos a conexo.
32 br.close();
33 conexo.close();
34 }
35 // Se houve problemas com o nome do host...
36 catch (UnknownHostException e)
37 {
38 System.out.println("O servidor no existe ou est fora do ar.");
39 }
40 // Se houve problemas genricos de entrada e sada...
41 catch (IOException e)
42 {
43 System.out.println("Erro de entrada e sada.");
44 }
45 }
46 }
Uma nota interessante sobre a aplicao mostrada na listagem 1: aps terminar a leitura
da string vinda do servidor, devemos manualmente fechar a conexo com o mesmo
(pois sabemos, de acordo com seu protocolo, que somente uma string ser enviada a
cada conexo). Se usarmos o aplicativo telnet para acessar este servio, o mesmo
automaticamente encerrar a conexo com o servidor.
1 package cap312;
2 import java.io.BufferedReader;
3 import java.io.BufferedWriter;
4 import java.io.IOException;
5 import java.io.InputStreamReader;
6 import java.io.OutputStreamWriter;
7 import java.net.Socket;
8 import java.net.UnknownHostException;
9
10 /**
11 * Esta classe implementa um cliente simples para o servio echo (porta 7).
12 * A classe simplesmente cria um socket para um servidor (no exemplo,
Cliente Servidor
Incio Incio
Cria conexo
L string do teclado
Sinal de trmino?
sim
no
Encerra conexo
Fim
Considere que seja necessrio por algum razo inverter uma string. A inverso de uma
string a simples modificao da ordem de seus caracteres para que a mesma seja lida
ao contrrio, ou da direita para a esquerda. Como um exemplo, a inverso da string
Java seria avaJ. O algoritmo de inverso simples, basta criar uma string vazia e
concatenar a esta string cada caracter da string original, lidos de trs para frente.
O diagrama mostra uma nfase no passo Inverte string pois este realiza o que, em
princpio, o cliente no saberia como ou teria recursos para processar. Em muitos ca-
sos de aplicaes cliente-servidor este passo seria o mais crucial: o processamento da
informao do lado do servidor.
1 package cap312;
2 import java.io.BufferedReader;
3 import java.io.BufferedWriter;
4 import java.io.IOException;
5 import java.io.InputStreamReader;
4 Curiosamente,se usarmos o mtodo showInputDialog da classe JOptionPane, a aplicao no ser terminada correta-
mente para isso deveremos usar o mtodo System.exit ao final da aplicao.
Cliente Servidor
Incio Incio
Cria conexo
L string do teclado
Inverte string
Fim
6 import java.io.OutputStreamWriter;
7 import java.net.BindException;
8 import java.net.ServerSocket;
9 import java.net.Socket;
10
11 /**
12 * Esta classe implementa um servidor simples que fica aguardando conexes de
13 * clientes. Quando uma conexo solicitada, o servidor recebe do cliente uma
14 * string, a inverte e envia este resuldado para o cliente, fechando a conexo.
15 */
16 public class ServidorDeStringsInvertidas
17 {
18 // Mtodo que permite a execuo da classe.
19 public static void main(String[] args)
20 {
21 ServerSocket servidor;
22 try
23 {
24 // Criamos a instncia de ServerSocket que responder por solicitaes
25 // porta 10101.
26 servidor = new ServerSocket(10101);
27 // O servidor aguarda "para sempre" as conexes.
28 while(true)
29 {
30 // Quando uma conexo feita,
31 Socket conexo = servidor.accept();
32 // ... o servidor a processa.
33 processaConexo(conexo);
34 }
35 }
36 // Pode ser que a porta 10101 j esteja em uso !
37 catch (BindException e)
38 {
39 System.out.println("Porta j em uso.");
40 }
41 // Pode ser que tenhamos um erro qualquer de entrada ou sada.
42 catch (IOException e)
43 {
44 System.out.println("Erro de entrada ou sada.");
45 }
46 }
47
Vamos ver como podemos escrever um servidor para servir instncias de classes em
Java. O cliente tambm dever ser capaz de receber do servidor estas instncias. Vamos
usar a classe Livro (listagem 4) para criar as instncias que sero enviadas.
Listagem 4: A classe Livro
1 package cap312;
2 import java.io.Serializable;
3
22 }
Para que instncias de classes possam ser enviadas e recebidas por servidores e clien-
tes necessrio que elas sejam serializveis. Para isto, basta declarar a classe como
implementando a interface Serializable, sem precisar implementar nenhum mtodo
Cliente Servidor
Incio Incio
Cria conexo
Executa mtodo da
instncia lida
Fim
1 package cap312;
2 import java.io.IOException;
3 import java.io.ObjectOutputStream;
4 import java.net.BindException;
5 import java.net.ServerSocket;
6 import java.net.Socket;
7 import java.util.ArrayList;
8
9 /**
10 * Esta classe implementa um servidor simples que fica aguardando conexes de
72 conexo.close();
73 }
74 // Se houve algum erro de entrada ou sada...
75 catch (IOException e)
76 {
77 System.out.println("Erro atendendo a uma conexo !");
78 }
79 }
80 }
Para acessar este servio, no podemos usar clientes como telnet: uma conexo feita
via telnet para o servidor executando esta aplicao retornaria strings com alguns ca-
racteres de controle (correspondente serializao de uma instncia da classe Livro)
que torna os resultados da interao praticamente inutilizveis. Precisamos de um cli-
ente especializado em receber e processar instncias da classe Livro.
1 package cap312;
2 import java.io.IOException;
3 import java.io.ObjectInputStream;
4 import java.net.Socket;
5 import java.net.UnknownHostException;
6
8 /**
9 * Esta classe implementa um cliente simples para o servio de livros.
10 * Ele se conecta ao servidor (pela porta 12244) e recebe uma instncia da classe
11 * Livro enviada pelo servidor.
12 */
13 public class ClienteDeLivros
14 {
15 public static void main(String[] args)
16 {
17 String servidor = "localhost";
18 // Tentamos fazer a conexo e ler uma linha...
19 try
20 {
21 Socket conexo = new Socket(servidor,12244);
22 // A partir do socket podemos obter um InputStream, a partir deste um
23 // ObjectInputStream.
24 ObjectInputStream dis = new ObjectInputStream(conexo.getInputStream());
25 Livro umLivro = (Livro)dis.readObject();
26 System.out.println("Livro obtido do servidor:");
27 umLivro.imprime();
28 // Fechamos a conexo.
29 dis.close();
30 conexo.close();
31 }
32 // Se houve problemas com o nome do host...
33 catch (UnknownHostException e)
34 {
35 System.out.println("O servidor no existe ou est fora do ar.");
36 }
37 // Se houve problemas genricos de entrada e sada...
38 catch (IOException e)
39 {
40 System.out.println("Erro de entrada e sada.");
41 }
42 // Essa exceo poderia ocorrer se tivssemos o cliente sendo executado em
43 // outro computador e a classe Livro no tivesse sido distribuda.
44 catch (ClassNotFoundException e)
45 {
46 System.out.println("A classe Livro no est presente no cliente.");
47 }
48 }
49 }
Existe uma outra diferena entre este cliente e outros: este deve, obrigatoriamente, ter
um bloco catch para processar a exceo ClassNotFoundException, que ser criada
caso a classe cuja instncia desejamos recuperar no existir do lado do cliente. Embora
para finalidade de testes esta classe deva estar sempre presente, importante lembrar
que em aplicaes mais complexas o servidor pode enviar uma instncia de uma classe
que no exista no cliente quando a aplicao do lado cliente for distribuda para uso,
devemos sempre lembrar de incluir todas as classes que podem ser serializadas para
aquela aplicao.
5 OK, so pseudo-aleatrios, mas para as finalidades deste documento vamos ignorar a diferena entre nmeros realmente
aleatrios e os gerados pelo mtodo Math.random.
Cliente Servidor
Incio Incio
Cria conexo
Fim
1 package cap312;
2 import java.io.DataOutputStream;
3 import java.io.IOException;
4 import java.net.BindException;
5 import java.net.ServerSocket;
6 import java.net.Socket;
7
8 /**
9 * Esta classe implementa um servidor simples que fica aguardando conexes de
10 * clientes. Quando uma conexo solicitada, o servidor envia para o cliente
11 * um nmero aleatrio e fecha a conexo.
12 */
13 public class ServidorDeNumerosAleatorios
14 {
15 // Mtodo que permite a execuo da classe.
16 public static void main(String[] args)
17 {
18 ServerSocket servidor;
19 try
20 {
21 // Criamos a instncia de ServerSocket que responder por solicitaes
22 // porta 9999.
23 servidor = new ServerSocket(9999);
24 // O servidor aguarda "para sempre" as conexes.
25 while(true)
26 {
27 // Quando uma conexo feita,
28 Socket conexo = servidor.accept();
29 // ... o servidor a processa.
30 processaConexo(conexo);
31 }
32 }
O servidor de nmeros aleatrios est pronto para receber conexes pela porta 9999,
mas os clientes existentes no so capazes de receber bytes correspondentes a valores
1 package cap312;
2 import java.io.DataInputStream;
3 import java.io.IOException;
4 import java.net.Socket;
5 import java.net.UnknownHostException;
6
8 /**
9 * Esta classe implementa um cliente simples para o servio de nmeros aleatrios.
10 * Ele se conecta ao servidor (pela porta 9999) e recebe um nmero aleatrio
11 * gerado no servidor.
12 */
13 public class ClienteDeNumerosAleatorios
14 {
15 public static void main(String[] args)
16 {
17 String servidor = "localhost";
18 // Tentamos fazer a conexo e ler uma linha...
19 try
20 {
21 Socket conexo = new Socket(servidor,9999);
22 // A partir do socket podemos obter um InputStream, a partir deste um
23 // DataInputStream.
24 DataInputStream dis = new DataInputStream(conexo.getInputStream());
25 double valor = dis.readDouble();
26 System.out.println("Li o valor "+valor+" do servidor "+servidor+".");
27 // Fechamos a conexo.
28 dis.close();
29 conexo.close();
30 }
31 // Se houve problemas com o nome do host...
32 catch (UnknownHostException e)
33 {
34 System.out.println("O servidor no existe ou est fora do ar.");
35 }
36 // Se houve problemas genricos de entrada e sada...
37 catch (IOException e)
38 {
39 System.out.println("Erro de entrada e sada.");
40 }
41 }
42 }
Cliente Servidor
Incio Incio
Cria conexo
L nome do arquivo
Seleciona arquivo e envia
selecionado
Fim
1 package cap312;
2 import java.io.BufferedReader;
3 import java.io.DataInputStream;
4 import java.io.DataOutputStream;
5 import java.io.File;
6 import java.io.FileInputStream;
7 import java.io.IOException;
8 import java.io.InputStreamReader;
9 import java.net.BindException;
10 import java.net.ServerSocket;
11 import java.net.Socket;
12
13 /**
14 * Esta classe implementa um servidor simples que fica aguardando conexes de
15 * clientes. Este servidor, quando conectado, envia uma lista de arquivos locais
16 * para o cliente, aguarda a seleo de um nome de arquivo e envia o contedo
17 * deste arquivo para o cliente.
18 */
19 public class ServidorDeArquivos
20 {
21 // Mtodo que permite a execuo da classe.
22 public static void main(String[] args)
23 {
24 try
25 {
26 // Criamos a instncia de ServerSocket que responder por solicitaes
27 // porta 2048.
28 ServerSocket servidor = new ServerSocket(2048);
29 // O servidor aguarda "para sempre" as conexes.
30 while(true)
31 {
32 // Quando uma conexo feita,
33 Socket conexo = servidor.accept();
34 // ... o servidor a processa.
35 processaConexo(conexo);
36 }
37 }
38 // Pode ser que a porta j esteja em uso !
39 catch (BindException e)
40 {
41 System.out.println("Porta j em uso.");
42 }
43 // Pode ser que tenhamos um erro qualquer de entrada ou sada.
44 catch (IOException e)
45 {
46 System.out.println("Erro de entrada ou sada.");
47 }
48 }
49
85 selecionado.length()+" bytes)");
86 sada.flush();
87 // Abrimos o arquivo localmente.
88 DataInputStream entradaLocal =
89 new DataInputStream(new FileInputStream(selecionado));
90 // Lemos todos os bytes do arquivo local, enviando-os para o cliente.
91 // Para maior eficincia, vamos ler e enviar os dados em blocos de 25 bytes.
92 byte[] arrayDeBytes = new byte[25];
93 while(true)
94 {
95 // Tentamos ler at 25 bytes do arquivo de entrada.
96 int resultado = entradaLocal.read(arrayDeBytes,0,25);
97 if (resultado == -1) break;
98 // Escrevemos somente os bytes lidos.
99 sada.write(arrayDeBytes,0,resultado);
100 }
101 // Ao terminar de ler o arquivo local, o fechamos.
102 entradaLocal.close();
103 // Ao terminar de atender a requisio, fechamos a stream de sada.
104 sada.close();
105 // Fechamos tambm a conexo.
106 conexo.close();
107 }
108 // Se houve algum erro de entrada ou sada...
109 catch (IOException e)
110 {
111 System.out.println("Erro atendendo a uma conexo !");
112 e.printStackTrace();
113 }
114 }
115 }
que ser encerrado quando no for mais possvel ler bytes do arquivo local) e o
cliente monitorar estes bytes lidos para verificar o final da transmisso. Desta
forma, demonstramos duas maneiras de verificar se todos os dados de uma sesso
de comunicao foram enviados pelo servidor ou cliente: um usando marcadores
ou tags que indicam final de transmisso e outro usando mtodos da API de Java.
Vejamos agora o cliente para este servidor de arquivos. No poderemos usar o cliente
telnet pois em determinado momento da comunicao o servidor enviar bytes para o
cliente, que devem ser armazenados em um arquivo e no mostrados na tela. Um cliente
adequado mostrado na classe ClienteDeArquivos (listagem 10).
Listagem 10: Cliente de arquivos
1 package cap312;
2 import java.io.BufferedWriter;
3 import java.io.DataInputStream;
4 import java.io.DataOutputStream;
5 import java.io.EOFException;
6 import java.io.FileOutputStream;
7 import java.io.IOException;
8 import java.io.OutputStreamWriter;
9 import java.net.Socket;
10 import java.net.UnknownHostException;
11
12 /**
13 * Esta classe implementa um cliente simples para o servidor de arquivos.
14 * A principal diferena entre este cliente e um cliente simples de texto
15 * (telnet, por exemplo) que existe uma ordem no protocolo de comunicao
16 * entre cliente-servidor que pede que em determinado momento, ao invs de
17 * receber textos para mostrar no terminal, o cliente deve receber dados para
18 * armazenar em um arquivo.
19 */
20 public class ClienteDeArquivos
21 {
22 public static void main(String[] args)
23 {
24 String servidor = "localhost";
25 // Tentamos fazer a conexo...
26 try
27 {
28 Socket conexo = new Socket(servidor,2048);
29 // A partir do socket podemos obter um InputStream, a partir deste um
30 // InputStreamReader e partir deste, um BufferedReader.
31 DataInputStream entrada =
32 new DataInputStream(conexo.getInputStream());
33 // A partir do socket podemos obter um OutputStream, a partir deste um
34 // OutputStreamWriter e partir deste, um BufferedWriter.
35 BufferedWriter sada =
36 new BufferedWriter(
37 new OutputStreamWriter(conexo.getOutputStream()));
38 // Lemos a lista de arquivos do servidor. Sabemos que vamos ler um
39 // nmero desconhecido de linhas do servidor. Usamos um lao que
40 // l linhas enquanto existirem dados a ser lidos. O servidor enviar
41 // a string ##### quando no houverem mais dados.
42 while(true)
43 {
44 String linha = entrada.readUTF();
Nesta seo veremos por que que alguns servidores devem estar preparados para aten-
der mltiplas requisies simultaneamente e como podemos preparar servidores para
esta tarefa.
Embora o diagrama da figura 12 parea mais complicado do que os outros, a nica di-
ferena fundamental que existem dois laos, do lado do cliente e do lado do servidor,
que garantem que o mesmo nmero de valores ser requisitado e lido.
1 package cap312;
2 import java.io.DataInputStream;
3 import java.io.DataOutputStream;
4 import java.io.IOException;
5 import java.net.BindException;
6 import java.net.ServerSocket;
7 import java.net.Socket;
8
9 /**
10 * Esta classe implementa um servidor simples que fica aguardando conexes de
11 * clientes. Quando uma conexo solicitada, o servidor l do cliente a
12 * quantidade de nmeros aleatrios desejada e envia para o cliente
13 * estes nmeros aleatrios, terminando ento a conexo.
14 */
15 public class SegundoServidorDeNumerosAleatorios
16 {
17 // Mtodo que permite a execuo da classe.
18 public static void main(String[] args)
19 {
20 ServerSocket servidor;
21 try
22 {
23 // Criamos a instncia de ServerSocket que responder por solicitaes
Cliente Servidor
Incio Incio
Cria conexo
Aindaexistem Aindaexistem
valores valores
aserlidos? aserenviados?
N N
S S
Fim
Figura 12: Protocolo de comunicao entre o cliente e o servidor de nmeros aleatrios (segunda verso)
24 // porta 9999.
25 servidor = new ServerSocket(9999);
26 // O servidor aguarda "para sempre" as conexes.
27 while(true)
28 {
29 // Quando uma conexo feita,
30 Socket conexo = servidor.accept();
31 // ... o servidor a processa.
32 processaConexo(conexo);
33 }
34 }
35 // Pode ser que a porta 9999 j esteja em uso !
36 catch (BindException e)
37 {
38 System.out.println("Porta j em uso.");
39 }
40 // Pode ser que tenhamos um erro qualquer de entrada ou sada.
41 catch (IOException e)
42 {
43 System.out.println("Erro de entrada ou sada.");
44 }
45 }
46
O cliente para este servio tambm precisa ser reescrito. O cliente para a segunda verso
do servidor de nmeros aleatrios mostrado na listagem 12.
Listagem 12: Segunda verso do cliente de nmeros aleatrios
1 package cap312;
2 import java.io.DataInputStream;
3 import java.io.DataOutputStream;
4 import java.io.IOException;
5 import java.net.Socket;
6 import java.net.UnknownHostException;
7
Fazer clientes aguardarem sua vez sem maiores informaes - no existe maneira
de informar aos clientes quanto tempo eles tero que esperar na fila para atendi-
mento (analogia: telefone ocupado).
Executar mais de um servidor simultaneamente, em portas diferentes - se a pri-
meira tentativa de conexo fracassar, o cliente dever descobrir, por conta prpria,
qual das portas que oferecem o servio est desocupada (analogia: vrios telefones
para a mesma pessoa, alguns ocupados).
Limitar a quantidade de nmeros a serem servidos para que a conexo seja liberada
o mais rpido possvel para outros clientes.
Evidentemente estas opes so muito restritivas. Uma outra alternativa, mais interes-
sante, seria fazer uso de linhas de execuo ou threads. Basicamente threads permitem
que aplicaes executem mais de uma tarefa de forma aparentemente simultnea. Con-
tinuamos com uma aplicao que tem um nico mtodo main, mas durante a execuo
deste mtodo ele cria vrias instncias de classes que podem ser executadas concorren-
temente. Para escrever um servidor capaz de tratar vrias requisies de forma aparen-
temente simultnea, podemos usar os conceitos de threads e as classes em Java que os
implementam.
1 package cap312;
2 /**
11 /**
12 * O construtor da classe inicializa o nome do carro e a velocidade do mesmo.
13 */
14 public CarroDeCorrida(String n,int vel)
15 {
16 nome = n;
17 distncia = 0;
18 velocidade = vel;
19 }
20
21 /**
22 * Este mtodo imprime os passos percorridos pelo carro.
23 */
24 public void executa()
25 {
26 while(distncia <= 1200)
27 {
28 System.out.println(nome+" rodou "+distncia+" km.");
29 distncia += velocidade;
30 // Pausa o processamento com um clculo intil.
31 for(int sleep=0;sleep<1000000;sleep++)
32 {
33 double x = Math.sqrt(Math.sqrt(Math.sqrt(sleep)));
34 }
35 }
36 }
37
38 }
A classe CarroDeCorrida (listagem 13) realmente simples, tendo como mtodos so-
mente o construtor e um mtodo executa que executar a simulao para a instncia
da classe. A simulao consiste em mudar a distncia percorrida pelo carro, imprimir
na tela e fazer uma pequena pausa (artificialmente criada por um lao que executa uma
operao matemtica).
A simulao de uma corrida poderia ser feita atravs de uma classe com vrias instn-
cias da classe CarroDeCorrida. A classe SimulacaoSemThreads, na listagem 14, cria
uma simulao simples.
Listagem 14: Simulao usando instncias de CarroDeCorrida.
1 package cap312;
2 /**
3 * Esta classe faz uma simulao de corrida usando instncias da classe
4 * CarroDeCorrida.
5 */
6 public class SimulacaoSemThreads
7 {
A forma mais simples para fazer com que as instncias possam ter um de seus mtodos
executados em paralelo com outros fazer a classe que contm o mtodo herdar da
classe Thread e implementar o mtodo run, que ser o mtodo a ser executado em
paralelo. Isto demonstrado na classe CarroDeCorridaIndependente, mostrada na
listagem 15.
Listagem 15: Classe que representa um carro de corrida para simulao (herdando de Thread).
1 package cap312;
2 /**
3 * Esta classe representa um carro da Corrida Maluca para uma simulao.
4 * Esta verso da classe herda da classe Thread, ento o mtodo run de
5 * instncias desta classe poder ser executado independentemente.
6 */
7 public class CarroDeCorridaIndependente extends Thread
8 {
9 private String nome;
10 private int distncia;
11 private int velocidade;
12
13 /**
14 * O construtor da classe inicializa o nome do carro e a velocidade do mesmo.
15 */
16 public CarroDeCorridaIndependente(String n,int vel)
17 {
18 nome = n;
19 distncia = 0;
20 velocidade = vel;
21 }
22
23 /**
24 * Este mtodo imprime a distncia percorrida at agora.
25 */
26 public void run()
27 {
28 while(distncia <= 1200)
29 {
30 System.out.println(nome+" rodou "+distncia+" km.");
31 distncia += velocidade;
32 // Pausa o processamento com um clculo intil.
33 for(int sleep=0;sleep<1000000;sleep++)
34 {
35 double x = Math.sqrt(Math.sqrt(Math.sqrt(sleep)));
36 }
37 }
38 }
39
40 }
importante observar que a assinatura do mtodo run deve obrigatoriamente ser public
void este mtodo no deve receber argumentos nem relanar excees.
1 package cap312;
2 /**
3 * Esta classe faz uma simulao de corrida usando instncias da classe
4 * CarroDeCorridaIndependente.
5 */
6 public class SimulacaoComThreads
7 {
8 // Este mtodo permite a execuo da classe.
9 public static void main(String[] args)
10 {
11 // Criamos instncias da classe CarroDeCorrida.
12 CarroDeCorridaIndependente penlope =
13 new CarroDeCorridaIndependente("Penlope Charmosa",60);
14 CarroDeCorridaIndependente dick =
15 new CarroDeCorridaIndependente("Dick Vigarista",100);
16 CarroDeCorridaIndependente quadrilha =
17 new CarroDeCorridaIndependente("Quadrilha da Morte",120);
18 // Criados os carros, vamos executar as simulaes.
19 penlope.start();
20 dick.start();
21 quadrilha.start();
22 }
23 }
Os passos para transformar uma classe que implementa um servidor sem mltiplas li-
nhas de execuo para classes que implementam servidores com mltiplas linhas de
execuo so, ento:
1. Criar uma classe que implementa o atendimento a uma nica conexo. Esta classe
dever herdar da classe Thread, ter um construtor (para possibilitar o armazena-
mento da instncia de Socket relacionada com a conexo que deve ser atendida
por uma instncia desta mesma classe) e o mtodo run, que dever ser respon-
1 package cap312;
2 import java.io.DataInputStream;
3 import java.io.DataOutputStream;
4 import java.io.IOException;
5 import java.net.Socket;
6
7 /**
8 * Esta classe representa o processamento que deve ser feito quando uma
9 * nica requisio for feita a um servidor. A classe herda de Thread para que
10 * vrias instncias dela possam ser executadas concorrentemente.
11 */
12 public class ServicoDeNumerosAleatorios extends Thread
13 {
14 // Precisamos armazenar o socket correspondente conexo.
15 private Socket conexo = null;
16
17 /**
18 * O construtor desta classe recebe como argumento uma instncia de Socket
19 * e o armazena em um campo da classe.
20 */
21 public ServicoDeNumerosAleatorios(Socket conn)
22 {
23 conexo = conn;
24 }
25
26 /**
27 * Este mtodo executa a rotina de atendimento a uma conexo com o servidor.
28 */
29 public void run()
30 {
31 try
32 {
33 // Criamos uma stream para receber valores nativos, usando a stream de entrada
34 // associado conexo.
35 DataInputStream entrada =
36 new DataInputStream(conexo.getInputStream());
37 // Criamos uma stream para enviar valores nativos, usando a stream de sada
38 // associado conexo.
39 DataOutputStream sada =
40 new DataOutputStream(conexo.getOutputStream());
41 // Lemos do cliente quantos nmeros ele deseja.
42 int quantidade = entrada.readInt();
43 // Enviamos para o cliente os nmeros.
44 for(int q=0;q<quantidade;q++)
45 {
46 double rand = Math.random();
47 sada.writeDouble(rand);
48 // Para demonstrar que realmente funciona, vamos imprimir um log.
49 System.out.println("Acabo de enviar o nmero "+rand+" para o cliente "+
50 conexo.getRemoteSocketAddress());
51 }
52 // Ao terminar de atender a requisio, fechamos as streams.
53 entrada.close();
54 sada.close();
55 // Fechamos tambm a conexo.
56 conexo.close();
57 }
58 // Se houve algum erro de entrada ou sada...
59 catch (IOException e)
60 {
61 System.out.println("Erro atendendo a uma conexo !");
62 }
63 }
64
65 }
A classe que representa o servidor tambm foi modificada de acordo com os passos in-
dicados. A classe TerceiroServidorDeNumerosAleatorios contm agora somente o
mtodo main que cria novas instncias de ServicoDeNumerosAleatorios quando no-
vas conexes so estabelecidas, e que executa o mtodo start destas instncias, retor-
nando o controle ao mtodo main imediatamente. A classe TerceiroServidorDeNu-
merosAleatorios mostrada na listagem 18.
Listagem 18: Terceira verso do servidor de nmeros aleatrios
1 package cap312;
2 import java.io.IOException;
3 import java.net.BindException;
4 import java.net.ServerSocket;
5 import java.net.Socket;
6
7 /**
8 * Esta classe implementa um servidor simples que fica aguardando conexes de
9 * clientes. Quando uma conexo solicitada, o servidor l do cliente a
10 * quantidade de nmeros aleatrios desejada e envia para o cliente
11 * estes nmeros aleatrios, terminando ento a conexo.
12 */
13 public class TerceiroServidorDeNumerosAleatorios
14 {
15 // Mtodo que permite a execuo da classe.
16 public static void main(String[] args)
17 {
18 ServerSocket servidor;
19 try
20 {
21 // Criamos a instncia de ServerSocket que responder por solicitaes
22 // porta 9999.
23 servidor = new ServerSocket(9999);
24 // O servidor aguarda "para sempre" as conexes.
25 while(true)
26 {
27 // Quando uma conexo feita,
28 Socket conexo = servidor.accept();
29 // ... criamos um servio para atender a esta conexo...
30 ServicoDeNumerosAleatorios s = new ServicoDeNumerosAleatorios(conexo);
31 // ... e executamos o servio (que ser executado independentemente).
32 s.start();
33 }
34 }
35 // Pode ser que a porta 9999 j esteja em uso !
36 catch (BindException e)
37 {
38 System.out.println("Porta j em uso.");
39 }
40 // Pode ser que tenhamos um erro qualquer de entrada ou sada.
41 catch (IOException e)
42 {
43 System.out.println("Erro de entrada ou sada.");
44 }
45 }
46 }
O cliente desta classe no precisa de modificaes, como cliente podemos usar a classe
SegundoClienteDeNumerosAleatorios (listagem 12).
1 2 3
O algoritmo que verifica se houve um vencedor para o jogo tambm simples. Existem
oito combinaes de posies que se forem ocupadas pelo mesmo jogador determinam
a vitria deste jogador: se as trs linhas, trs colunas ou duas diagonais do tabuleiro
forem totalmente preenchidas pelo mesmo jogador, este ganhou o jogo. As setas mos-
tradas na figura 13 indicam estas combinaes.
Para que um jogo possa ser executado, so necessrios dois jogadores (dois clientes).
Conforme mencionado anteriormente, os clientes no se conectam e enviam/recebem
informaes do servidor simultaneamente (usando linhas de execuo): a comunicao
feita por vezes, uma vez sendo a de um cliente/jogador e a vez seguinte sendo do outro.
Cria conexo
Aguarda conexo
Cria conexo
Venceuo
jogo?
S
N
Venceuo
N jogo?
Fim Fim
1 package cap312;
2 import java.io.BufferedReader;
3 import java.io.BufferedWriter;
4 import java.io.IOException;
5 import java.io.InputStreamReader;
6 import java.io.OutputStreamWriter;
7 import java.net.BindException;
8 import java.net.ServerSocket;
9 import java.net.Socket;
10
11 /**
12 * Esta classe implementa um servidor de jogo-da-velha. Este servidor aguarda
13 * a conexo de dois clientes e gerencia o jogo entre eles.
14 */
15 public class ServidorDeJogoDaVelha
16 {
17 // Declaramos uma matriz de caracteres como sendo o tabuleiro do jogo.
18 private static char[][] tabuleiro;
19
87 // Este mtodo executa a lgica do jogo, tendo acesso aos mecanismos de entrada
88 // e sada de duas conexes.
89 private static void processaJogo()
90 {
91 // A primeira coisa a fazer "limpar" o tabuleiro.
92 for(int linha=0;linha<3;linha++)
93 for(int coluna=0;coluna<3;coluna++)
94 tabuleiro[linha][coluna] = ;
95 // String que ser reusada para as entradas de comandos.
96 String jogada;
97 // Coordenadas da jogada.
98 int linha,coluna;
99 // Pea do vencedor.
100 char vencedor;
101 try
102 {
103 // Enviamos o tabuleiro para os dois jogadores pela primeira vez.
104 mostraTabuleiro();
105 // Executamos um lao "eterno"
106 while(true)
107 {
108 // Lemos e verificamos a jogada do primeiro jogador.
109 enviaMensagem(sada2,"Aguarde movimento do jogador X.");
110 enviaMensagem(sada1,"Jogador X, entre seu movimento.");
111 jogada = entrada1.readLine();
112 enviaMensagem(sada1,"Jogador X escolheu "+jogada);
113 enviaMensagem(sada2,"Jogador X escolheu "+jogada);
114 // Quais so as coordenadas da jogada ?
115 linha = jogada.charAt(0)-A; // A = 0; B = 1; C = 2;
116 coluna = jogada.charAt(1)-1; // 1 = 0; 2 = 1; 3 = 2;
117 // A jogada vlida ?
118 if ((linha >= 0) && (linha <= 2) &&
119 (coluna >= 0) && (coluna <= 2) &&
120 (tabuleiro[linha][coluna] == ))
121 {
122 tabuleiro[linha][coluna] = X;
123 }
124 else
125 {
126 enviaMensagem(sada1,"Jogada do jogador X em posio invlida.");
127 enviaMensagem(sada2,"Jogada do jogador X em posio invlida.");
128 }
129 // Enviamos o tabuleiro para os dois jogadores.
130 mostraTabuleiro();
131 // Verificamos se algum venceu o jogo.
132 vencedor = verificaVencedor();
133 if (vencedor == V)
134 {
135 mostraTabuleiro();
136 enviaMensagem(sada1,"Empate!");
137 enviaMensagem(sada2,"Empate!");
138 break;
139 }
140 else if (vencedor != )
141 {
142 mostraTabuleiro();
143 enviaMensagem(sada1,"Vencedor: jogador "+vencedor);
144 enviaMensagem(sada2,"Vencedor: jogador "+vencedor);
145 break;
146 }
147 // Lemos e verificamos a jogada do segundo jogador.
148 enviaMensagem(sada1,"Aguarde movimento do jogador O.");
149 enviaMensagem(sada2,"Jogador O, entre seu movimento.");
150 jogada = entrada2.readLine();
151 enviaMensagem(sada1,"Jogador O escolheu "+jogada);
152 enviaMensagem(sada2,"Jogador O escolheu "+jogada);
153 // Quais so as coordenadas da jogada ?
154 linha = jogada.charAt(0)-A; // A = 0; B = 1; C = 2;
155 coluna = jogada.charAt(1)-1; // 1 = 0; 2 = 1; 3 = 2;
156 // A jogada vlida ?
157 if ((linha >= 0) && (linha <= 2) &&
158 (coluna >= 0) && (coluna <= 2) &&
159 (tabuleiro[linha][coluna] == ))
160 {
161 tabuleiro[linha][coluna] = O;
162 }
163 else
164 {
165 enviaMensagem(sada1,"Jogada do jogador O em posio invlida.");
166 enviaMensagem(sada2,"Jogada do jogador O em posio invlida.");
167 }
168 // Enviamos o tabuleiro para os dois jogadores.
169 mostraTabuleiro();
170 // Verificamos se algum venceu o jogo.
171 vencedor = verificaVencedor();
172 if (vencedor == V)
173 {
174 mostraTabuleiro();
175 enviaMensagem(sada1,"Empate!");
176 enviaMensagem(sada2,"Empate!");
177 break;
178 }
179 else if (vencedor != )
180 {
181 enviaMensagem(sada1,"Vencedor: jogador "+vencedor);
194 /**
195 * Este mtodo mostra o tabuleiro do jogo para os dois clientes. Ele monta
196 * uma string contendo o tabuleiro (inclusive movimentos j jogados) com alguma
197 * decorao para o usurio saber que posies ainda podem ser jogadas. A string
198 * ento enviada para os dois clientes.
199 */
200 private static void mostraTabuleiro()
201 {
202 String tabuleiroFormatado = "";
203 String tempLinha;
204 tabuleiroFormatado += " \n";
205 tabuleiroFormatado += " 1 2 3 \n";
206 tabuleiroFormatado += " +-+-+-+\n";
207 for(int linha=0;linha<3;linha++)
208 {
209 tempLinha = (char)(A+linha)+"|";
210 for(int coluna=0;coluna<3;coluna++)
211 tempLinha += tabuleiro[linha][coluna]+"|";
212 tempLinha += "\n";
213 tabuleiroFormatado += tempLinha;
214 tabuleiroFormatado += " +-+-+-+\n";
215 }
216 enviaMensagem(sada1,tabuleiroFormatado);
217 enviaMensagem(sada2,tabuleiroFormatado);
218 }
219
220 /**
221 * Este mtodo verifica se houve algum vencedor considerando a situao atual do
222 * tabuleiro. Se houver vencedor, o mtodo retorna o caracter correspondente ao
223 * vencedor (X ou O), seno retorna espao.
224 */
225 private static char verificaVencedor()
226 {
227 // Vamos verificar as 8 possveis combinaes para ganhar o jogo.
228 // Primeira linha.
229 if ((tabuleiro[0][0] == tabuleiro[0][1]) &&
230 (tabuleiro[0][1] == tabuleiro[0][2])) return tabuleiro[0][0];
231 // Segunda linha.
232 else if ((tabuleiro[1][0] == tabuleiro[1][1]) &&
233 (tabuleiro[1][1] == tabuleiro[1][2])) return tabuleiro[1][0];
234 // Terceira linha.
235 else if ((tabuleiro[2][0] == tabuleiro[2][1]) &&
236 (tabuleiro[2][1] == tabuleiro[2][2])) return tabuleiro[2][0];
237 // Primeira coluna.
238 else if ((tabuleiro[0][0] == tabuleiro[1][0]) &&
239 (tabuleiro[1][0] == tabuleiro[2][0])) return tabuleiro[0][0];
240 // Segunda coluna.
241 else if ((tabuleiro[0][1] == tabuleiro[1][1]) &&
242 (tabuleiro[1][1] == tabuleiro[2][1])) return tabuleiro[0][1];
264 /**
265 * Este mtodo facilita o envio de mensagens para os clientes, executando
266 * o mtodos write, newLine e flush de uma instncia de BufferedWriter.
267 */
268 private static void enviaMensagem(BufferedWriter bw,String mensagem)
269 {
270 try
271 {
272 bw.write(mensagem);
273 bw.newLine();
274 bw.flush();
275 }
276 catch (IOException e)
277 {
278 System.out.println("Erro enviando mensagem.");
279 }
280 }
281
282 }
Consideremos uma tarefa computacional cujo tempo para execuo seja potencialmente
longo, mas que possa ser dividida em subtarefas menores. Podemos escrever uma apli-
cao servidora que ser executada ao mesmo tempo em vrios computadores, cada
uma responsvel pela soluo de uma parte do problema. Podemos criar uma aplicao
cliente que solicita a cada aplicao servidora a execuo de sua parte, e que integra as
solues em uma s.
f(x)
a b
a b
delta
de seus dados.
Nesta seo veremos um exemplo de tarefa computacional que pode ser dividida, en-
viada a servidores para processamento e integrada pelo cliente, alcanando assim um
possvel tempo menor de execuo quando comparado com a execuo em um nico
computador.
Na parte superior da figura 8.1 temos uma funo f (x) definida entre os pontos A e B.
O valor da integral de f (x) entre A e B a rea mostrada em cinza na figura 8.1. Uma
maneira de calcular esta rea de forma aproximada dividir a rea em muitos peque-
nos trapzios que cobrem a mesma rea, como mostrado na parte inferior da figura 8.1.
Para calcular a rea coberta pela funo basta ento calcular a somatria das reas dos
trapzios. Considerando a funo f (x) entre os pontos A e B e que a rea da funo
ser dividida de forma que a largura da base de cada trapzio seja igual a delta, pode-
mos calcular a rea do mesmo como sendo a somatria da rea do trapzio cuja base
delta, lado direito igual a f (a) e lado esquerdo igual a f (a + delta), ou seja, igual a
delta ( f (a) + f (a + delta))/2.
De posse do mtodo e equaes acima, fcil ver que podemos dividir o problema da
somatria em problemas menores, onde cada um deles, para ser executado, dever re-
ceber o valor de A (primeiro valor, ou valor inferior para clculo), B (segundo valor, ou
valor superior), delta e claro, a funo a ser integrada.
1 package cap312;
2 import java.io.DataInputStream;
3 import java.io.DataOutputStream;
4 import java.io.IOException;
5 import java.net.BindException;
6 import java.net.ServerSocket;
7 import java.net.Socket;
8
9 /**
10 * Esta classe implementa um servidor simples que fica aguardando conexes de
11 * clientes. Quando uma conexo solicitada, o servidor l do cliente o
12 * intervalo e preciso para o clculo da funo, efetua o clculo e retorna
13 * para o cliente o resultado.
14 */
15 public class ServidorDeCalculoDeIntegrais
16 {
17 // Mtodo que permite a execuo da classe.
18 public static void main(String[] args)
19 {
20 // O nmero da porta ser obtido da linha de comando.
21 int porta = Integer.parseInt(args[0]);
22 ServerSocket servidor;
23 try
24 {
25 // Criamos a instncia de ServerSocket que responder por solicitaes
26 // porta.
27 servidor = new ServerSocket(porta);
Cliente Servidor 1
Incio Incio
Divide tarefa em
subtarefas
Cria conexo
Efetua clculo
Aguarda todos os
resultados
Imprime resultado
Fim
Figura 17: Protocolo para aplicao que faz o clculo de uma integral
46 }
47 }
48
87 /**
88 * Este mtodo calcula a integral de uma funo entre os valores passados
89 * usando como delta o valor tambm passado. O mtodo usa a regra do
90 * trapzio.
91 */
92 private static double calculaIntegral(double incio,double fim,double delta)
93 {
94 double a = incio;
95 double somaDasreas = 0;
96 // Vamos percorrendo os valores para argumentos da funo...
97 while((a+delta) <= fim)
98 {
99 double alturaA = funo(a);
100 double alturaB = funo(a+delta);
101 // Calculamos a rea do trapzio local.
102 double reaTrapzio = delta*(alturaA+alturaB)/2;
103 // Somamos rea total.
104 somaDasreas += reaTrapzio;
105 a += delta;
106 }
110 /**
111 * Este mtodo calcula uma funo em determinado ponto.
112 */
113 private static double funo(double argumento)
114 {
115 return Math.sin(argumento)*Math.sin(argumento);
116 }
117
118 }
1 package cap312;
2 import java.io.DataInputStream;
6 Usaremos o valor do resultado desejado (/4) para comparar o resultado obtido, mas j sabendo de antemo que os
resultados no sero exatamente iguais por causa de vrios fatores: impreciso do valor /4, erros de arredondamento naturais
e preciso do algoritmo de clculo dependente do valor delta.
3 import java.io.DataOutputStream;
4 import java.io.IOException;
5 import java.net.Socket;
6 import java.net.UnknownHostException;
7
8 /**
9 * Esta classe representa o processamento que deve ser feito quando uma
10 * requisio de clculo de intgrais for feita a um servidor.
11 * A classe herda de Thread para que vrias instncias dela possam ser
12 * executadas concorrentemente.
13 */
14 public class LinhaDeExecucaoDeCalculoDeIntegrais extends Thread
15 {
16 // Precisamos armazenar o socket correspondente conexo.
17 private Socket conexo = null;
18 // Tambm precisamos armazenar os valores para clculo.
19 private double incio,fim,delta,resultado;
20
21 /**
22 * O construtor desta classe recebe como argumento o nmero da porta do
23 * servidor e o armazena em um campo da classe. O construtor tambm recebe
24 * como argumentos o intervalo e delta para clculo da integral.
25 */
26 public LinhaDeExecucaoDeCalculoDeIntegrais(String servidor,int porta,
27 double i,double f,double d)
28 {
29 try
30 {
31 conexo = new Socket(servidor,porta);
32 }
33 catch (UnknownHostException e)
34 {
35 System.out.println("Host desconhecido !");
36 }
37 catch (IOException e)
38 {
39 System.out.println("Erro de entrada ou sada !");
40 }
41 incio = i;
42 fim = f;
43 delta = d;
44 }
45
46 /**
47 * Este mtodo executa a rotina de atendimento a uma conexo com o servidor.
48 */
49 public void run()
50 {
51 try
52 {
53 // Criamos uma stream para receber valores nativos, usando a stream de entrada
54 // associado conexo.
55 DataInputStream entrada =
56 new DataInputStream(conexo.getInputStream());
57 // Criamos uma stream para enviar valores nativos, usando a stream de sada
58 // associado conexo.
59 DataOutputStream sada =
60 new DataOutputStream(conexo.getOutputStream());
61 // Enviamos ao servidor o intervalo da funo.
62 sada.writeDouble(incio);
63 sada.writeDouble(fim);
88 }
A classe que implementa o cliente, que por sua vez ir criar algumas instncias da classe
LinhaDeExecucaoDeCalculoDeIntegrais, a classe ClienteDeCalculoDeInte-
grais, mostrada na listagem 22.
Listagem 22: O cliente de clculo de integrais
1 package cap312;
2 /**
3 * Esta classe implementa um cliente simples para o servio de clculo de
4 * integrais.
5 * Ele se conecta a dois servidores (pela portas nas quais estes servidores
6 * esto respondendo), envia trechos para clculo da integral e calcula a soma
7 * dos resultados.
8 */
9 public class ClienteDeCalculoDeIntegrais
10 {
11 public static void main(String[] args)
12 {
13 String servidor = "localhost";
14 // Dividimos a tarefa em duas metades que sero executadas com diferentes
15 // precises.
16 LinhaDeExecucaoDeCalculoDeIntegrais l1 =
17 new LinhaDeExecucaoDeCalculoDeIntegrais("localhost",11111,
18 0,Math.PI/4,0.000001);
19 LinhaDeExecucaoDeCalculoDeIntegrais l2 =
20 new LinhaDeExecucaoDeCalculoDeIntegrais("localhost",11112,
21 Math.PI/4,Math.PI/2,0.0000001);
22 // Iniciamos a execuo das duas tarefas.
23 l1.start();
24 l2.start();
25 // Aguardamos at que as duas instncias tenham terminado de processar
26 // o mtodo run.
27 while(l1.isAlive() || l2.isAlive())
28 {
29 }
30 // Calculamos o resultado final e comparamos com o esperado.
31 double resFinal = l1.getResultado()+l2.getResultado();
32 System.out.println("Resultado:"+resFinal);
33 System.out.println("Esperado :"+Math.PI/4);
34 }
35 }
Para garantir que o mtodo getResultado somente ser executado depois que o mtodo
run tiver terminado seu processamento, podemos criar um lao infinito que aguarda
at que o resultado dos mtodos isAlive das classes que herdam de Thread sejam
ambos false este mtodo verifica se uma linha de execuo ainda est viva, se
o mtodo retorna true se a linha de execuo ainda est sendo executada. Ao final
do processamento basta somar os resultados obtidos pelas duas linhas de execuo e
apresentar o resultado esperado para comparao.
9 Mais informaes
Considero este documento ainda inacabado existem outros tpicos interessantes que
podemos explorar, como por exemplo:
Rafael Santos
Maro de 2004