[Resolvido] Problema com o exemplo de chat do livro do Deitel

Caros,

estou tentando implementar um chat, seguindo o exemplo apresentado no livro.

Bem, consegui me conectar ao ServerMessenger certinho...

Quando eu envio a primeira mensagem... dá tudo certo...

A mensagem chega no servidor e é distribuída para todos os clientes....

Só que quando envio a segunda mensagem ou o outro cliente vai responder, acontece o seguinte:


No server dá o seguinte erro: 

[color=red]
java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(Unknown Source)
    at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
    at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
    at sun.nio.cs.StreamDecoder.read(Unknown Source)
    at java.io.BufferededReader.fill(Unknown Source)
    at java.io BufferededReader.readLine(Unknown Source)
    at java.io BufferededReader.readLine(Unknown Source)
    at chat.ReceivingThread.run(ReceivingThread.java:51)
[/color]

A minha classe ReceivingThread é essa:

[code]package chat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.net.Socket;
import java.util.StringTokenizer;

// Thread que espera mensagens de um cliente 
// particular e envia mensagens para um MessageListener;
// espera novas mensagens de clientes do MessengerServer em Threads separadas
public class ReceivingThread extends Thread implements SocketMessengerConstants{

        private BufferedReader input;
    private MessageListener messageListener;
    private boolean keepListening = true;

    // construtor
    public ReceivingThread(MessageListener listener, Socket socketCliente) {
	
	    // invoca o construtor da super classe para dar nome à Thread
	    super("ReceivingThread: " + socketCliente);
	
	    // configura o ouvinte para o qual a novas mensagens devem ser enviadas
	    messageListener = listener;
	
	    // configura o tempo máximo de espera para leitura do socketCliente
	    // e cria um BufferedReader para ler as mensagens que chegam
	    try {
		    socketCliente.setSoTimeout(30000);
		
		    input = new BufferedReader(new InputStreamReader(socketCliente.getInputStream()));
		
	    } catch (IOException e) {
		
		    e.printStackTrace();
	    }
    }

    // espera novas mensagens e as envia ao MessageListener
    public void run(){
	
	    String message;
	
	    // espera novas mensagens até que seja parado
	    while (keepListening){
		
		    // lê mensagem do BufferedReader
		    try{
			    message = input.readLine();
		
			    // trata exceção quando o tempo máximo para leitura é esgotado
		    }catch (InterruptedIOException interruptedIOException){				
			    continue;
		
		    }catch (IOException e){
			    e.printStackTrace();
			    break;
		    }
		
		    // assegura que a mensagem não está vazia
		    if(message != null){
			
			    // separa a mensagem em tokens para recuperar 
			    //o nome do usuário e o corpo da mensagem
			    StringTokenizer stringTokenizer = new StringTokenizer(message, MESSAGE_SEPARATOR);
			
			    // ignora mensagens que não têm um nome de usuário e um corpo de mensagem
			    if(stringTokenizer.countTokens() == 2){
				
				    // envia mensagem para o MessageListener
				    messageListener.messageReceived(
						    stringTokenizer.nextToken(),   // nome do usuario
						    stringTokenizer.nextToken()); // corpo da mensagem
			    }
			    else 
				
				    // se recebeu mensagem de desconexão, para de esperar mensagens
				    if(message.equalsIgnoreCase(MESSAGE_SEPARATOR + DISCONNECT_STRING)){
					    stopListening();
				    }
		    }
		
	    }
	
	    // fecha o BufferedReader (também fecha o socket)
	    try{
		    input.close();
	    }catch (IOException e){
		    e.printStackTrace();
	    }
    }

    // para de esperar por mensagens
    public void stopListening(){
	    keepListening = false;
    }
}[/code]

E no cliente dá o seguinte erro:

[color=red]java.net.SocketException: Socket closed
at java.net.PlainDatagramSocketImpl.receive0(Native Method)
at java.net.PlainDatagramSocketImpl.receive(Unknown Source)
at java.net.DatagramSocket.receive(Unknown Source)
at chat.PacketReceivingThread.run(PacketReceivingThread.java:62)[/color]

A minha classe PacketReceivingThread é a seguinte:

[code]package chat;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.StringTokenizer;

public class PacketReceivingThread extends Thread implements SocketMessengerConstants{

    // MessageListener ao qual as mensagens devem ser entregues
    private MessageListener messageListener;

    // Multicatsocket para receber as mensagens transmitidas
    private MulticastSocket multicastSocket;

    // InetAddress do grupo de mensagens
    private InetAddress multicastGrupo;

    // indicador para terminar a PacketReceivingThread
    private boolean keepListening = true;

    // construtor
    public PacketReceivingThread(MessageListener listener) {
	
	    super("PacketReceivingThread");
	
	    messageListener = listener;

	    // conecta o MulticastSocket ao endereco e a porta de multicast
	    try{
		    multicastSocket = new MulticastSocket(MULTICAST_LISTENING_PORT);
		
		    multicastGrupo = InetAddress.getByName(MULTICAST_ADDRESS);
		
		    // junta-se ao grupo de multicast para receber mensagens
		    multicastSocket.joinGroup(multicastGrupo);
		
		    // ajusta tempo máximo de 5 segundos para esperar novos pacotes
		    multicastSocket.setSoTimeout(20000);
	
	    }catch (IOException e) {
		    e.printStackTrace();
	    }
    }

    // espera as mensagens do grupo de multicast
    public void run(){
	
	    // espera as mensagens até ser parada
	    while(keepListening){
		
		    // cria buffer para mensagens que chegam
		    byte[] buffer = new byte[MESSAGE_SIZE];
	
		    // cria DatagramPacket para mensagen que chega
		    DatagramPacket datagramPacket = new DatagramPacket(buffer, MESSAGE_SIZE);
		
		    // recebe novo DatagramPacket (chamada bloqueante)
		    try{
			    multicastSocket.receive(datagramPacket);
		
		    }catch (InterruptedIOException interruptedIOException){
			    interruptedIOException.printStackTrace();
		
		    }catch (IOException e){
			    e.printStackTrace();
			    break;
		    }
		
		    // coloca dados da mensagem em uma String
		    String message = new String(datagramPacket.getData());
		
		    // assegura que a mensagem não está vazia
		    if(message != null){
			
			    // elimina espaço em branco extra no fim da mensagem
			    message = message.trim();
			
			    // separa a mensagem em tokens para separar nome do usuario do corpo da mensagem
			    StringTokenizer stringTokenizer = new StringTokenizer(message, MESSAGE_SEPARATOR);
			
			    // ignora mensagens que não têm nome de usuario e corpo
			    if(stringTokenizer.countTokens() == 2){
				
				    // envia a mensagem para o MessageListener
				    messageListener.messageReceived(stringTokenizer.nextToken(), stringTokenizer.nextToken());
			    }
		    }
		
		    // sai do grupo de multicast e fecha o MulticastSocket
		    try{
			    multicastSocket.leaveGroup(multicastGrupo);
			    multicastSocket.close();
		
		    }catch (IOException e){
			    e.printStackTrace();
		    }
	    }
	
    }

    // para de esperar por novas mensagens
    public void stopListening(){
	    keepListening = false;
    }

}[/code]

Depurando eu percebi que na classe ReceivingThread do Servidor...
A execução fica muito tempo na linha 51 

[code]message = input.readLine();[/code]

Até cair na Exception InterruptedIOException

Alguém sabe me dizer o porquê?

Obrigada!

Olá amigo, fica complicado você expor exercicios do livro do Deitel em um Forúm de Java onde as pessoas no minimo vem aqui já trocar informações ou mesmo citar partes de codigos onde a interpretação já advem de um profissional mais informado, claro que não deixa de ser válida.

Entretando existe uma comunidade JavaLivros onde pessoa que tem o mesmo livro que você comprou já testou o codigo e já leu também a obra, eu recomendo você a frequentar o JavaLivros e levar essa informação para lá também, eu vou verificar o codigo mas eu não tenho o livro do Deitel pra lhe acompanhar…

[size=18][color=orange]Comunidade JavaLivros[/color] [/size]
:arrow: http://javalivros.ning.com/

Abraçoss…

Vejo duas classes que recebem os dados, mas cadê a que manda?

Ok.

Do lado cliente:

[code]package chat;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;

// SendingThread para entregar mensagens enviadas ao servidor
public class SendingThread extends Thread implements SocketMessengerConstants{

// socket pelo qual a mensagem deve ser enviada
private Socket socketCliente;
private String messageToSend;

// construtor
public SendingThread(Socket socket, String userName, String message) {
	
	super("SendingThread:" + socket);
	
	socketCliente = socket;
	
	// constroi a mensagem a ser enviada
	messageToSend = userName + MESSAGE_SEPARATOR + message;
}

// envia a mensagem e sai da thread
public void run(){
	
	// envia a mensagem e descarrega PrintWriter
	try{
		PrintWriter printWriter = new PrintWriter(socketCliente.getOutputStream());
		printWriter.println(messageToSend);
		printWriter.flush();
	
	}catch (IOException e){
		e.printStackTrace();
	}
}

}[/code]

Do lado servidor:

package chat;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

// entrega mensagens enviadas para um grupo de multicast através de DatagramPackets
public class MulticastSendingThread extends Thread implements SocketMessengerConstants{
	
	// dados da mensagem
	private byte[] messageBytes;
	
	// construtor
	public MulticastSendingThread(byte[] bytes) {
		
		// invoca o construtor da superclasse para nomear a Thread
		super("MulticastSendingThread");
		
		messageBytes = bytes;
		
	}
	
	// entrega a mensagem ao MULTICAST_ADDRESS através do DatagramSocket
	public void run(){
		
		// entrega a mensagem
		try{
			
			// cria o DatagramSocket para enviar a mensagem
			DatagramSocket datagramSocket = new DatagramSocket(MULTICAST_SENDING_PORT);
			
			// usa o InetAddress reservado para o grupo de Multicast
			InetAddress grupo = InetAddress.getByName(MULTICAST_ADDRESS);
			
			// cria o DatagramPacket que contém a mensagem
			DatagramPacket datagramPacket = new DatagramPacket(messageBytes, messageBytes.length,
					grupo, MULTICAST_LISTENING_PORT);
			
			// envia o pacote para um grupo de multicast e fecha o socket
			datagramSocket.send(datagramPacket);
			datagramSocket.close();
			
		}catch (IOException e){
			e.printStackTrace();
		}
	}
	

}

Fora o cliente não usar o método close no PrintWriter, não detectei nada de errado, olhando por cima.

Bem, adicionei o método close ao Printwriter e quando eu vou enviar a segunda mensagem,
dá esse erro aqui:

[color=red]java.net.SocketException: Socket is closed
at java.net.Socket.getOutputStream(Unknown Source)
at chat.SendingThread.run(SendingThread.java:30)[/color]

Não acredito que seja isso… parece que acontece alguma coisa no servidor…

O que estou vendo é que o servidor sempre fecha a conexão quando recebe a mensagem, porem o Cliente sempre acha que a conexão está aberta do socket.

Bem, você tem que fazer eles entrarem num acordo.

Eu recomendo você implementar o Cliente para que ele veja se a conexão está aberta antes mandar a mensagem. Se não estiver, que ele requisite uma conexão com o servidor da classe que controla isso.

Bruno, era isso mesmo… o servidor estava fechando a conexão a toda hora…

Fui repassando pelas classes para ver por que isso acontecia e adivinha só…

Na classe PacketReceivingThread sem querer eu coloquei o bloco try catch

que sai do grupo de multicast e fecha o MulticastSocket dentro do while(keepListening):

[code]// espera as mensagens até ser parada
while(keepListening){

		    // cria buffer para mensagens que chegam
		    byte[] buffer = new byte[MESSAGE_SIZE];
	
		    // cria DatagramPacket para mensagen que chega
		    DatagramPacket datagramPacket = new DatagramPacket(buffer, MESSAGE_SIZE);
		
		    // recebe novo DatagramPacket (chamada bloqueante)
		    try{
			    multicastSocket.receive(datagramPacket);
		
		    }catch (InterruptedIOException interruptedIOException){
			    interruptedIOException.printStackTrace();
		
		    }catch (IOException e){
			    e.printStackTrace();
			    break;
		    }
		
		    // coloca dados da mensagem em uma String
		    String message = new String(datagramPacket.getData());
		
		    // assegura que a mensagem não está vazia
		    if(message != null){
			
			    // elimina espaço em branco extra no fim da mensagem
			    message = message.trim();
			
			    // separa a mensagem em tokens para separar nome do usuario do corpo da mensagem
			    StringTokenizer stringTokenizer = new StringTokenizer(message, MESSAGE_SEPARATOR);
			
			    // ignora mensagens que não têm nome de usuario e corpo
			    if(stringTokenizer.countTokens() == 2){
				
				    // envia a mensagem para o MessageListener
				    messageListener.messageReceived(stringTokenizer.nextToken(), stringTokenizer.nextToken());
			    }
		    }
		
		    // sai do grupo de multicast e fecha o MulticastSocket
		    try{
			    multicastSocket.leaveGroup(multicastGrupo);
			    multicastSocket.close();
		
		    }catch (IOException e){
			    e.printStackTrace();
		    }
	    }[/code]

Por isso que após a primeira mensagem o socket já era fechado.

Foi só tirar de dentro do while que funcionou… rs… :smiley:

Ai,ai! Que newba! ><’
:oops:

Vlw pela ajuda, Bruno! :wink:

ola, gostaria de saber o que virou o projeto
pois estou fazendo também e estou com problemas