9. Código-fonte dos programas
9.1. O cliente genérico TCP
Muitos serviços criados nos primórdios da Internet funcionam de acordo com o modelo do servidor de eco estudado anteriormente: as trocas cliente-servidor ocorrem por meio de trocas de linhas de texto. Vamos escrever um cliente TCP genérico que será iniciado da seguinte maneira: java cltTCPgenerique servidor porta
Esse cliente TCP se conectará à porta port do servidor serveur. Feito isso, ele criará duas threads:
- um thread responsável por ler os comandos digitados no teclado e enviá-los ao servidor
- um thread responsável por ler as respostas do servidor e exibi-las na tela
Por que duas threads? Cada serviço TCP-IP possui seu próprio protocolo, e às vezes ocorrem as seguintes situações:
- o cliente precisa enviar várias linhas de texto antes de receber uma resposta
- a resposta de um servidor pode conter várias linhas de texto
Portanto, o ciclo de envio de uma única linha ao servidor — recebimento de uma única linha enviada pelo servidor — nem sempre é adequado. Assim, vamos criar dois ciclos separados:
- um ciclo para ler os comandos digitados no teclado a serem enviados ao servidor. O usuário indicará o fim dos comandos com a palavra-chave fin.
- um ciclo de recepção e exibição das respostas do servidor. Esse será um ciclo infinito que só será interrompido pelo fechamento do fluxo de rede pelo servidor ou pelo usuário no teclado, ao digitar o comando fin.
Para que esses dois loops sejam independentes, precisamos de dois threads independentes. Vamos mostrar um exemplo de execução em que nosso cliente TCP genérico se conecta a um serviço SMTP (Protocolo de Transferência SendMail). Esse serviço é responsável pelo encaminhamento de e-mails aos seus destinatários. Ele opera na porta 25 e utiliza um protocolo de comunicação do tipo troca de linhas de texto.
Dos>java clientTCPgenerique istia.univ-angers.fr 25
Commandes :
<-- 220 istia.univ-angers.fr ESMTP Sendmail 8.11.6/8.9.3; Mon, 13 May 2002 08:37:26 +0200
help
<-- 502 5.3.0 Sendmail 8.11.6 -- HELP not implemented
mail from: machin@univ-angers.fr
<-- 250 2.1.0 machin@univ-angers.fr... Sender ok
rcpt to: serge.tahe@istia.univ-angers.fr
<-- 250 2.1.5 serge.tahe@istia.univ-angers.fr... Recipient ok
data
<-- 354 Enter mail, end with "." on a line by itself
Subject: test
ligne1
ligne2
ligne3
.
<-- 250 2.0.0 g4D6bks25951 Message accepted for delivery
quit
<-- 221 2.0.0 istia.univ-angers.fr closing connection
[fin du thread de lecture des réponses du serveur]
fin
[fin du thread d'envoi des commandes au serveur]
Vamos comentar essas trocas entre cliente e servidor:
- o serviço SMTP envia uma mensagem de boas-vindas quando um cliente se conecta a ele:
- alguns serviços possuem um comando help que fornece informações sobre os comandos que podem ser utilizados com o serviço. Neste caso, não é assim. Os comandos SMTP utilizados no exemplo são os seguintes:
- mail from: expéditeur, para indicar o endereço de e-mail do remetente da mensagem
- rcpt to: destinataire, para indicar o endereço de e-mail do destinatário da mensagem. Se houver vários destinatários, o comando rcpt to: deve ser repetido quantas vezes forem necessárias para cada um deles.
- data, que sinaliza ao servidor SMTP que a mensagem será enviada. Conforme indicado na resposta do servidor, trata-se de uma sequência de linhas terminada por uma linha contendo apenas o caractere ponto. Uma mensagem pode ter cabeçalhos separados do corpo da mensagem por uma linha em branco. Em nosso exemplo, definimos um assunto com a palavra-chave Subject:
- assim que a mensagem for enviada, é possível indicar ao servidor que terminamos com o comando quit. O servidor então encerra a conexão de rede. O thread de leitura pode detectar esse evento e ser encerrado.
- O usuário então digita “fin” no teclado para interromper também o thread de leitura dos comandos digitados no teclado.
Se verificarmos o e-mail recebido, temos o seguinte (Outlook):

Observe-se que o serviço SMTP não consegue detectar se um remetente é válido ou não. Portanto, nunca se pode confiar no campo from de uma mensagem. Neste caso, o remetente machin@univ-angers.fr não existia.
Esse cliente TCP genérico pode nos permitir descobrir o protocolo de comunicação dos serviços da Internet e, a partir daí, criar classes especializadas para os clientes desses serviços. Vamos descobrir o protocolo de comunicação do serviço POP (Post Office Protocol), que permite recuperar e-mails armazenados em um servidor. Ele opera na porta 110.
Dos> java clientTCPgenerique istia.univ-angers.fr 110
Commandes :
<-- +OK Qpopper (version 4.0.3) at istia.univ-angers.fr starting.
help
<-- -ERR Unknown command: "help".
user st
<-- +OK Password required for st.
pass monpassword
<-- +OK st has 157 visible messages (0 hidden) in 11755927 octets.
list
<-- +OK 157 visible messages (11755927 octets)
<-- 1 892847
<-- 2 171661
...
<-- 156 2843
<-- 157 2796
<-- .
retr 157
<-- +OK 2796 octets
<-- Received: from lagaffe.univ-angers.fr (lagaffe.univ-angers.fr [193.49.144.1])
<-- by istia.univ-angers.fr (8.11.6/8.9.3) with ESMTP id g4D6wZs26600;
<-- Mon, 13 May 2002 08:58:35 +0200
<-- Received: from jaume ([193.49.146.242])
<-- by lagaffe.univ-angers.fr (8.11.1/8.11.2/GeO20000215) with SMTP id g4D6wSd37691;
<-- Mon, 13 May 2002 08:58:28 +0200 (CEST)
...
<-- ------------------------------------------------------------------------
<-- NOC-RENATER2 Tl. : 0800 77 47 95
<-- Fax : (+33) 01 40 78 64 00 , Email : noc-r2@cssi.renater.fr
<-- ------------------------------------------------------------------------
<--
<-- .
quit
<-- +OK Pop server at istia.univ-angers.fr signing off.
[fin du thread de lecture des réponses du serveur]
fin
[fin du thread d'envoi des commandes au serveur]
Os principais comandos são os seguintes:
- user login, onde se insere o nome de usuário na máquina que hospeda nossos e-mails
- pass password, onde se insere a senha associada ao login anterior
- list, para obter a lista de mensagens no formato número, tamanho em bytes
- retr i, para ler a mensagem nº i
- quit, para encerrar a sessão.
Vamos agora conhecer o protocolo de comunicação entre um cliente e um servidor Web, que normalmente opera na porta 80:
Dos> java clientTCPgenerique istia.univ-angers.fr 80
Commandes :
GET /index.html HTTP/1.0
<-- HTTP/1.1 200 OK
<-- Date: Mon, 13 May 2002 07:30:58 GMT
<-- Server: Apache/1.3.12 (Unix) (Red Hat/Linux) PHP/3.0.15 mod_perl/1.21
<-- Last-Modified: Wed, 06 Feb 2002 09:00:58 GMT
<-- ETag: "23432-2bf3-3c60f0ca"
<-- Accept-Ranges: bytes
<-- Content-Length: 11251
<-- Connection: close
<-- Content-Type: text/html
<--
<-- <html>
<--
<-- <head>
<-- <meta http-equiv="Content-Type"
<-- content="text/html; charset=iso-8859-1">
<-- <meta name="GENERATOR" content="Microsoft FrontPage Express 2.0">
<-- <title>Bienvenue a l'ISTIA - Universite d'Angers</title>
<-- </head>
....
<-- face="Verdana"> - Dernire mise jour le <b>10 janvier 2002</b></font></p>
<-- </body>
<-- </html>
<--
[fin du thread de lecture des réponses du serveur]
fin
[fin du thread d'envoi des commandes au serveur]
Um cliente web envia seus comandos ao servidor de acordo com o seguinte esquema:
Somente após receber a linha vazia é que o servidor web responde. No exemplo, utilizamos apenas um comando:
que solicita ao servidor o URL /index.html e indica que está trabalhando com o protocolo HTTP versão 1.0. A versão mais recente desse protocolo é a 1.1. O exemplo mostra que o servidor respondeu enviando o conteúdo do arquivo index.html e, em seguida, encerrou a conexão, já que é possível observar que o thread de leitura das respostas foi encerrado. Antes de enviar o conteúdo do arquivo index.html, o servidor web enviou uma série de cabeçalhos encerrada por uma linha em branco:
<-- HTTP/1.1 200 OK
<-- Date: Mon, 13 May 2002 07:30:58 GMT
<-- Server: Apache/1.3.12 (Unix) (Red Hat/Linux) PHP/3.0.15 mod_perl/1.21
<-- Last-Modified: Wed, 06 Feb 2002 09:00:58 GMT
<-- ETag: "23432-2bf3-3c60f0ca"
<-- Accept-Ranges: bytes
<-- Content-Length: 11251
<-- Connection: close
<-- Content-Type: text/html
<--
<-- <html>
A linha <html> é a primeira linha do arquivo /index.html. O que vem acima é chamado de cabeçalhos HTTP (Protocolo de Transferência HyperText). Não vamos detalhar esses cabeçalhos aqui, mas vale lembrar que nosso cliente genérico permite acessá-los, o que pode ser útil para compreendê-los. A primeira linha, por exemplo:
indica que o servidor web contatado compreende o protocolo HTTP/1.1 e que encontrou o arquivo solicitado (200 OK), sendo 200 um código de resposta HTTP. As linhas
informam ao cliente que ele receberá 11.251 bytes representando o texto HTML (HyperText Markup Language) e que, ao final do envio, a conexão será encerrada.
Portanto, temos aqui um cliente TCP muito prático. Ele certamente faz menos do que o programa telnet que usamos anteriormente, mas foi interessante escrevê-lo nós mesmos. O programa do cliente TCP genérico é o seguinte:
// pacotes importados
import java.io.*;
import java.net.*;
public class clientTCPgenerique{
// recebe como parâmetro as características de um serviço na forma
// servidor porta
// conecta-se ao serviço
// cria um thread para ler comandos digitados no teclado
// esses comandos serão enviados ao servidor
// cria um thread para ler as respostas do servidor
// elas serão exibidas na tela
// tudo termina com o comando “fin” digitado no teclado
// variável de instância
private static Socket client;
public static void main(String[] args){
// sintaxe
final String syntaxe="pg serveur port";
// número de argumentos
if(args.length != 2)
erreur(syntaxe,1);
// anota-se o nome do servidor
String serveur=args[0];
// a porta deve ser um número inteiro maior que 0
int port=0;
boolean erreurPort=false;
Exception E=null;
try{
port=Integer.parseInt(args[1]);
}catch(Exception e){
E=e;
erreurPort=true;
}
erreurPort=erreurPort || port <=0;
if(erreurPort)
erreur(syntaxe+"\n"+"Port incorrect ("+E+")",2);
client=null;
// podem ocorrer problemas
try{
// conectando-se ao serviço
client=new Socket(serveur,port);
}catch(Exception ex){
// erro
erreur("Impossible de se connecter au service ("+ serveur
+","+port+"), erreur : "+ex.getMessage(),3);
// fim
return;
}//catch
// são criados os threads de leitura/gravação
new ClientSend(client).start();
new ClientReceive(client).start();
// fim do thread principal
return;
}// main
// exibição de erros
public static void erreur(String msg, int exitCode){
// exibição de erro
System.err.println(msg);
// encerramento com erro
System.exit(exitCode);
}//erro
}//classe
class ClientSend extends Thread {
// classe responsável por ler comandos digitados no teclado
// e enviá-los a um servidor por meio de um cliente TCP passado como parâmetro
private Socket client; // o cliente TCP
// construtor
public ClientSend(Socket client){
// observa-se o cliente TCP
this.client=client;
}//construtor
// método Run da thread
public void run(){
// dados locais
PrintWriter OUT=null; // fluxo de gravação de rede
BufferedReader IN=null; // fluxo do teclado
String commande=null; // comando lido no teclado
// gerenciamento de erros
try{
// criação do fluxo de gravação de rede
OUT=new PrintWriter(client.getOutputStream(),true);
// criação do fluxo de entrada do teclado
IN=new BufferedReader(new InputStreamReader(System.in));
// ciclo de entrada e envio de comandos
System.out.println("Commandes : ");
while(true){
// leitura do comando digitado no teclado
commande=IN.readLine().trim();
// Concluído?
if (commande.toLowerCase().equals("fin")) break;
// envio do comando ao servidor
OUT.println(commande);
// próximo comando
}//while
}catch(Exception ex){
// erro
System.err.println("Envoi : L'erreur suivante s'est produite : " + ex.getMessage());
}//catch
// fim — fechamento dos fluxos
try{
OUT.close();client.close();
}catch(Exception ex){}
// sinaliza-se o fim do thread
System.out.println("[Envoi : fin du thread d'envoi des commandes au serveur]");
}//execução
}//classe
class ClientReceive extends Thread{
// classe responsável por ler as linhas de texto destinadas a um
// cliente TCP passado como parâmetro
private Socket client; // o cliente TCP
// construtor
public ClientReceive(Socket client){
// registramos o cliente TCP
this.client=client;
}//construtor
// método Run da thread
public void run(){
// dados locais
BufferedReader IN=null; // fluxo de leitura de rede
String réponse=null; // resposta do servidor
// gerenciamento de erros
try{
// criação do fluxo de leitura de rede
IN=new BufferedReader(new InputStreamReader(client.getInputStream()));
// ciclo de leitura das linhas de texto do fluxo IN
while(true){
// leitura do fluxo de rede
réponse=IN.readLine();
// fluxo encerrado?
if(réponse==null) break;
// exibição
System.out.println("<-- "+réponse);
}//while
}catch(Exception ex){
// erro
System.err.println("Réception : L'erreur suivante s'est produite : " + ex.getMessage());
}//catch
// fim — fechando os fluxos
try{
IN.close();client.close();
}catch(Exception ex){}
// notifica-se o fim do thread
System.out.println("[Réception : fin du thread de lecture des réponses du serveur]");
}//execução
}//classe
9.2. O servidor TCP genérico
Agora vamos nos concentrar em um servidor
- que exibe na tela os comandos enviados por seus clientes
- e lhes envia, como resposta, as linhas de texto digitadas no teclado por um usuário. Portanto, é o próprio usuário que atua como servidor.
O programa é executado por: java serveurTCPgenerique portEcoute, onde portEcoute é a porta à qual os clientes devem se conectar. O atendimento ao cliente será garantido por duas threads:
- um thread dedicado exclusivamente à leitura das linhas de texto enviadas pelo cliente
- um thread dedicado exclusivamente à leitura das respostas digitadas pelo usuário. Este sinalizará, por meio do comando fin, que está encerrando a conexão com o cliente.
O servidor cria duas threads por cliente. Se houver n clientes, haverá 2n threads ativas ao mesmo tempo. O servidor, por sua vez, nunca é encerrado, a menos que o usuário pressione Ctrl-C no teclado. Vejamos alguns exemplos.
O servidor é iniciado na porta 100 e usamos o cliente genérico para nos comunicarmos com ele. A janela do cliente é a seguinte:
E:\data\serge\MSNET\c#\rede\cliente tcp genérico> java clientTCPgenerique localhost 100
Commandes :
commande 1 du client 1
<-- réponse 1 au client 1
commande 2 du client 1
<-- réponse 2 au client 1
fin
L'erreur suivante s'est produite : Impossible de lire les données de la connexion de transport.
[fin du thread de lecture des réponses du serveur]
[fin du thread d'envoi des commandes au serveur]
As linhas que começam com <-- são as enviadas do servidor para o cliente; as demais, do cliente para o servidor. A janela do servidor é a seguinte:
Dos> java serveurTCPgenerique 100
Serveur générique lancé sur le port 100
Thread de lecture des réponses du serveur au client 1 lancé
1 : Thread de lecture des demandes du client 1 lancé
<-- commande 1 du client 1
réponse 1 au client 1
1 : <-- commande 2 du client 1
réponse 2 au client 1
1 : [fin du Thread de lecture des demandes du client 1]
fin
[fin du Thread de lecture des réponses du serveur au client 1]
As linhas que começam com <-- são aquelas enviadas do cliente para o servidor. As linhas N: são as linhas enviadas do servidor para o cliente nº N. O servidor acima ainda está ativo, enquanto o cliente 1 já foi encerrado. Iniciamos um segundo cliente para o mesmo servidor:
Dos> java clientTCPgenerique localhost 100
Commandes :
commande 3 du client 2
<-- réponse 3 au client 2
fin
L'erreur suivante s'est produite : Impossible de lire les données de la connexion de transport.
[fin du thread de lecture des réponses du serveur]
[fin du thread d'envoi des commandes au serveur]
A janela do servidor fica assim:
Dos> java serveurTCPgenerique 100
Serveur générique lancé sur le port 100
Thread de lecture des réponses du serveur au client 1 lancé
1 : Thread de lecture des demandes du client 1 lancé
<-- commande 1 du client 1
réponse 1 au client 1
1 : <-- commande 2 du client 1
réponse 2 au client 1
1 : [fin du Thread de lecture des demandes du client 1]
fin
[fin du Thread de lecture des réponses du serveur au client 1]
Thread de lecture des réponses du serveur au client 2 lancé
2 : Thread de lecture des demandes du client 2 lancé
<-- commande 3 du client 2
réponse 3 au client 2
2 : [fin du Thread de lecture des demandes du client 2]
fin
[fin du Thread de lecture des réponses du serveur au client 2]
^C
Vamos agora simular um servidor web, iniciando nosso servidor genérico na porta 88:
Dos> java serveurTCPgenerique 88
Serveur générique lancé sur le port 88
Agora, vamos abrir um navegador e acessar a página http://localhost:88/exemple.html. O navegador se conectará à porta 88 da máquina localhost e, em seguida, solicitará a página /exemple.html:

Vamos agora observar a janela do nosso servidor:
Dos>java serveurTCPgenerique 88
Serveur générique lancé sur le port 88
Thread de lecture des réponses du serveur au client 2 lancé
2 : Thread de lecture des demandes du client 2 lancé
<-- GET /exemple.html HTTP/1.1
<-- Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/msword, */*
<-- Accept-Language: fr
<-- Accept-Encoding: gzip, deflate
<-- User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705; .NET CLR 1.0.2
914)
<-- Host: localhost:88
<-- Connection: Keep-Alive
<--
Assim, identificamos os cabeçalhos HTTP enviados pelo navegador. Isso nos permite descobrir, aos poucos, o protocolo HTTP. Em um exemplo anterior, criamos um cliente web que enviava apenas o comando GET. Isso já havia sido suficiente. Vemos aqui que o navegador envia outras informações ao servidor. Elas têm como objetivo indicar ao servidor que tipo de cliente ele tem diante de si. Vemos também que os cabeçalhos HTTP terminam com uma linha em branco.
Vamos elaborar uma resposta para o nosso cliente. O usuário ao teclado é, neste caso, o verdadeiro servidor e pode elaborar uma resposta manualmente. Lembremo-nos da resposta fornecida por um servidor web em um exemplo anterior:
<-- HTTP/1.1 200 OK
<-- Date: Mon, 13 May 2002 07:30:58 GMT
<-- Server: Apache/1.3.12 (Unix) (Red Hat/Linux) PHP/3.0.15 mod_perl/1.21
<-- Last-Modified: Wed, 06 Feb 2002 09:00:58 GMT
<-- ETag: "23432-2bf3-3c60f0ca"
<-- Accept-Ranges: bytes
<-- Content-Length: 11251
<-- Connection: close
<-- Content-Type: text/html
<--
<-- <html>
Vamos tentar dar uma resposta semelhante:
...
<-- Host: localhost:88
<-- Connection: Keep-Alive
<--
2 : HTTP/1.1 200 OK
2 : Server: serveur tcp generique
2 : Connection: close
2 : Content-Type: text/html
2 :
2 : <html>
2 : <head><title>Serveur generique</title></head>
2 : <body>
2 : <center>
2 : <h2>Reponse du serveur generique</h2>
2 : </center>
2 : </body>
2 : </html>
2 : fin
L'erreur suivante s'est produite : Impossible de lire les données de la connexion de transport.
[fin du Thread de lecture des demandes du client 2]
[fin du Thread de lecture des réponses du serveur au client 2]
As linhas que começam com 2: são enviadas do servidor para o cliente nº 2. O comando fin encerra a conexão do servidor com o cliente. Limitamos nossa resposta aos seguintes cabeçalhos HTTP:
HTTP/1.1 200 OK
2 : Server: serveur tcp generique
2 : Connection: close
2 : Content-Type: text/html
2 :
Não informamos o tamanho do arquivo que vamos enviar (Content-Length), mas nos limitamos a indicar que vamos encerrar a conexão (Connection: close) após o envio do mesmo. Isso é suficiente para o navegador. Ao perceber que a conexão foi encerrada, ele saberá que a resposta do servidor foi concluída e exibirá a página HTML que lhe foi enviada. Esta última é a seguinte:
2 : <html>
2 : <head><title>Serveur generique</title></head>
2 : <body>
2 : <center>
2 : <h2>Reponse du serveur generique</h2>
2 : </center>
2 : </body>
2 : </html>
Em seguida, o usuário encerra a conexão com o cliente digitando o comando fin. O navegador reconhece então que a resposta do servidor foi concluída e pode exibi-la:

Se, no exemplo acima, digitarmos View/Source para ver o que o navegador recebeu, obtemos:

ou seja, exatamente o que foi enviado a partir do servidor genérico.
O código do servidor TCP genérico é o seguinte:
// pacotes
import java.io.*;
import java.net.*;
public class serveurTCPgenerique{
// programa principal
public static void main (String[] args){
// recebe as solicitações dos clientes na porta de escuta
// cria um thread para ler as solicitações do cliente
// essas solicitações serão exibidas na tela
// cria um thread para ler comandos digitados no teclado
// esses comandos serão enviados como resposta ao cliente
// tudo termina com o comando “fin” digitado no teclado
final String syntaxe="Syntaxe : pg port";
// variável de instância
// existe algum argumento
if(args.length != 1)
erreur(syntaxe,1);
// a porta deve ser um número inteiro >0
int port=0;
boolean erreurPort=false;
Exception E=null;
try{
port=Integer.parseInt(args[0]);
}catch(Exception e){
E=e;
erreurPort=true;
}
erreurPort=erreurPort || port <=0;
if(erreurPort)
erreur(syntaxe+"\n"+"Port incorrect ("+E+")",2);
// criamos o serviço de escuta
ServerSocket ecoute=null;
int nbClients=0; // número de clientes atendidos
try{
// criamos o serviço
ecoute=new ServerSocket(port);
// acompanhamento
System.out.println("Serveur générique lancé sur le port " + port);
// ciclo de atendimento aos clientes
Socket client=null;
while (true){ // loop infinito — será interrompido com Ctrl-C
// aguardando um cliente
client=ecoute.accept();
// o serviço é executado em threads separadas
nbClients++;
// são criadas as threads de leitura/gravação
new ServeurSend(client,nbClients).start();
new ServeurReceive(client,nbClients).start();
// retornamos à escuta de solicitações
}// fim do while
}catch(Exception ex){
// reporta-se o erro
erreur("L'erreur suivante s'est produite : " + ex.getMessage(),3);
}//catch
}// fim de main
// exibição dos erros
public static void erreur(String msg, int exitCode){
// exibição do erro
System.err.println(msg);
// parada com erro
System.exit(exitCode);
}//erro
}//classe
class ServeurSend extends Thread{
// classe responsável por ler respostas digitadas no teclado
// e enviá-las a um cliente por meio de um cliente TCP passado ao construtor
Socket client; // o cliente TCP
int numClient; // nº do cliente
// construtor
public ServeurSend(Socket client, int numClient){
// observa-se o cliente TCP
this.client=client;
// e seu n.º
this.numClient=numClient;
}//fabricante
// método Run da thread
public void run(){
// dados locais
PrintWriter OUT=null; // fluxo de gravação de rede
String réponse=null; // resposta lida no teclado
BufferedReader IN=null; // fluxo do teclado
// acompanhamento
System.out.println("Thread de lecture des réponses du serveur au client "+ numClient + " lancé");
// gerenciamento de erros
try{
// criação do fluxo de gravação de rede
OUT=new PrintWriter(client.getOutputStream(),true);
// criação do fluxo do teclado
IN=new BufferedReader(new InputStreamReader(System.in));
// ciclo de entrada e envio de comandos
while(true){
// identificação do cliente
System.out.print("--> " + numClient + " : ");
// Leitura da resposta digitada no teclado
réponse=IN.readLine().trim();
// Concluído?
if (réponse.toLowerCase().equals("fin")) break;
// envio da resposta ao servidor
OUT.println(réponse);
// próxima resposta
}//enquanto
}catch(Exception ex){
// erro
System.err.println("L'erreur suivante s'est produite : " + ex.getMessage());
}//catch
// fim — fechamento dos fluxos
try{
OUT.close();client.close();
}catch(Exception ex){}
// notifica-se o fim do thread
System.out.println("[fin du Thread de lecture des réponses du serveur au client "+ numClient+ "]");
}//execução
}//classe
class ServeurReceive extends Thread{
// classe responsável por ler as linhas de texto enviadas ao servidor
// por meio de um cliente TCP passado ao construtor
Socket client; // o cliente TCP
int numClient; // nº do cliente
// construtor
public ServeurReceive(Socket client, int numClient){
// observa-se o cliente TCP
this.client=client;
// e seu número
this.numClient=numClient;
}//fabricante
// método Run da thread
public void run(){
// dados locais
BufferedReader IN=null; // fluxo de leitura de rede
String réponse=null; // resposta do servidor
// acompanhamento
System.out.println("Thread de lecture des demandes du client "+ numClient + " lancé");
// gerenciamento de erros
try{
// criação do fluxo de leitura de rede
IN=new BufferedReader(new InputStreamReader(client.getInputStream()));
// loop de leitura das linhas de texto do fluxo IN
while(true){
// leitura do fluxo de rede
réponse=IN.readLine();
// fluxo encerrado?
if(réponse==null) break;
// exibição
System.out.println("<-- "+réponse);
}//while
}catch(Exception ex){
// erro
System.err.println("L'erreur suivante s'est produite : " + ex.getMessage());
}//catch
// fim — fechamos os fluxos
try{
IN.close();client.close();
}catch(Exception ex){}
// sinaliza-se o fim do thread
System.out.println("[fin du Thread de lecture des demandes du client "+ numClient+"]");
}//execução
}//classe