Gui bloqueada depois do THread

1 resposta
Y

Pessoal,

Existem algumas perguntas parecidas aqui no fórum, eu pesquisei e tudo mas não consigo compreender. Eu tenho um cliente e servidor simples de bate-papo (estou aprendendo), criei um micro-interface para o servidor com dois botões: conectar e desconectar. Quando eu executo o servidor, ele começa conectado automanticamente. Os clientes conversam e tudo o mais. Quando eu clico em desconectar, os clientes não são mais capazes de conversar.

Até aqui, tudo bem.

O problema é que quando eu clico em Conectar de novo, apesar de voltar a funcionar e os clientes poderem novamente voltar a conversar, a gui do aplicativo servidor fica bloqueada. Era para desabilitar o botão de Conectar e habilitar o botão de Desconectar, mas não funciona de jeito nenhum.

Alguém pode me ajudar???

Servidor:

import java.io.*;
import java.net.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class VerySimpleChatServer {
	ArrayList clientOutputStreams;
	JButton botaoAtivar;
	JButton botaoDesativar;
	ServerSocket serverSock;
	JLabel mensagem;
	Thread t;
	Iterator it;
	Socket sock;
	PrintWriter writer;
	Socket clientSocket;

	//Cria uma classe interna utilizando a interface Runnable
	//Para criar as conexões com os clientes (um thread para cada conexão)
	//E receber as mensagens e repassar para todos.
	public class ClientHandler implements Runnable {
		BufferedReader reader;

		//Declaração do construtor da classe do Runnable
		//Utiliza o soquete de uma conexão já aceita pelo servidor
		public ClientHandler(Socket clientSocket) {
			try {
				//Na existência de um soquete, cria um buffer para armazenar
				//os dados do fluxo de entrada do soquete.
				sock = clientSocket;
				InputStreamReader isReader = new InputStreamReader(sock.getInputStream());
				reader = new BufferedReader(isReader);
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}

		public void run() {
			String message;
			try {
				//Enquanto houver alguma linha a ser lida no fluxo de entrada
				//Imprimir no console e chamar o método tellEveryone
				//Que reenvia a mensagem para todas as partes
				while ((message = reader.readLine()) != null) {
					System.out.println("Server Read " + message);
					tellEveryone(message);
				}
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
	} //Fim da classe interna do Runnable

	//Método principal da classe do servidor.
	public static void main(String[] args) {
		VerySimpleChatServer servidor = new VerySimpleChatServer();
		servidor.gui();
	}
	
	public void gui() {
		JFrame frame = new JFrame("Bate-Papo Simples");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		JPanel painel = new JPanel();
		botaoAtivar = new JButton("Ativar");
		botaoAtivar.addActionListener(new ouvidorAtivar());
		botaoDesativar = new JButton("Desativar");
		botaoDesativar.addActionListener(new ouvidorDesativar());
		mensagem = new JLabel();
		
		botaoAtivar.setEnabled(false);
		botaoDesativar.setEnabled(true);
		mensagem.setText("O servidor está online");
		
		painel.add(botaoAtivar);
		painel.add(botaoDesativar);
		painel.add(mensagem);
		
		frame.getContentPane().add(BorderLayout.CENTER, painel);
		
		frame.setSize(300,100);
		frame.setVisible(true);
		
		go();
	}
	
	public class ouvidorAtivar implements ActionListener {
		public void actionPerformed(ActionEvent ev) {
			
			botaoAtivar.setEnabled(false);
			botaoDesativar.setEnabled(true);
			mensagem.setText("O servidor está online");
			
			conectar();
		}
	}
	
	public class ouvidorDesativar implements ActionListener {
		public void actionPerformed(ActionEvent ev) {
			
			botaoAtivar.setEnabled(true);
			botaoDesativar.setEnabled(false);
			mensagem.setText("O servidor está offline");
			
			desconectar();
		}
	}
	
	public void go() {
		clientOutputStreams = new ArrayList();
		try {
			//Criando o soquete do servidor na porta 5000
			serverSock = new ServerSocket(5000);
			while (true) {
				//Aceitar as conexões de entrada ao soquete
				clientSocket = serverSock.accept();
				//Chamando o método para enviar texto para clientes
				writer = new PrintWriter(clientSocket.getOutputStream());
				//Adicionando a um ArrayList
				clientOutputStreams.add(writer);
				//Criando um Thread utilizando a conexão aceita como assinatura
				t = new Thread(new ClientHandler(clientSocket));
				t.start();
				System.out.println("got a connection");
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	
	public void conectar() {
		go();
	}
	
	public void desconectar() {
		try {
			serverSock.close();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		clientOutputStreams.clear();
		writer.close();
		t.interrupt();
		while (!sock.isClosed()) {
			try {
				sock.close();
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
	}

	//Classe que replica as mensagens entre todos os clientes
	public void tellEveryone(String message) {
		//Pega o próximo dado do ArrayList
		it = clientOutputStreams.iterator();
		while(it.hasNext()) {
			try {
				//Escreve cada mensagem do ArrayList para todos os clientes
				PrintWriter writer = (PrintWriter) it.next();
				writer.println(message);
				writer.flush();
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
	}
}

Cliente

import java.io.*;
import java.net.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class SimpleChatClient {
	JTextArea incoming;
	JTextField outgoing;
	BufferedReader reader;
	PrintWriter writer;
	Socket sock;
	
	public static void main(String[] args) {
		SimpleChatClient client = new SimpleChatClient();
		client.go();
	}
	
	public void go() {
		JFrame frame = new JFrame("SOftware de Chat Simples");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		JPanel mainPanel = new JPanel();
		incoming = new JTextArea(15,25);
		incoming.setLineWrap(true);
		incoming.setWrapStyleWord(true);
		incoming.setEditable(false);
		JScrollPane qScroller = new JScrollPane(incoming);
		qScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
		qScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		outgoing = new JTextField(20);
		JButton sendButton = new JButton("Send");
		sendButton.addActionListener(new SendButtonListener());
		mainPanel.add(qScroller);
		mainPanel.add(outgoing);
		mainPanel.add(sendButton);
		setUpNetworking();
		
		Thread readerThead = new Thread(new IncomingReader());
		readerThead.start();
		
		frame.getContentPane().add(BorderLayout.CENTER, mainPanel);
		frame.setSize(400,300);
		frame.setVisible(true);
	}
	
	private void setUpNetworking() {
		try {
			sock = new Socket("127.0.0.1", 5000);
			InputStreamReader streamReader = new InputStreamReader(sock.getInputStream());
			reader = new BufferedReader(streamReader);
			writer = new PrintWriter(sock.getOutputStream());
			System.out.println("Networking Established.");
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}
	
	public class SendButtonListener implements ActionListener {
		public void actionPerformed(ActionEvent ev) {
			try {
				writer.println(outgoing.getText());
				writer.flush();
			} catch (Exception ex) {
				ex.printStackTrace();
			}
			outgoing.setText("");
			outgoing.requestFocus();
		}
	}
	
	public class IncomingReader implements Runnable {
		public void run() {
			String message;
			try {
				while ((message = reader.readLine()) != null) {
					System.out.println("Client Read " + message);
					incoming.append(message + "\n");
				}
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
	}
}

1 Resposta

ctosin

Olá,

É muito provável que o seu código esteja parado dentro do método go(), aqui:

clientSocket = serverSock.accept();

Este método é chamado como resultado do click num botão (através de um ActionListener). Enquanto o seu método do ActionListener não terminar, a sua GUI vai parar de responder. Isto é devido à própria arquitetura de funcionamento do Swing. Pra resolver isso, uma das alternativas é você chamar o método conectar() no seu action listener dentro de uma thread separada. Porque se você usar a mesma thread pra aguardar conexões dos clientes e pra sua GUI, sua GUI vai realmente parar de responder.

Abraço

Criado 21 de dezembro de 2009
Ultima resposta 21 de dez. de 2009
Respostas 1
Participantes 2