Olá pessoal.
Estou fazendo um programa de chat, bem simples, só para praticar sockets.
Enfim, minha dúvida é quanto ao tratamento dos clientes conectados. Para cada ServerSocket.accept() inicio uma nova Thread para receber as mensagens dos clientes.e trata-las.
Porém ao fechar meu ServerSocket, devo apenas iterar sobre as threads e interrompe-las, ou devo fechar cada socket primeiro?
Também gostaria de opiniões sobre meu código, para saber se estou no caminho certo ou estou fazendo muito errado.
Segue o código que tenho até agora do Server:
public class Server implements Runnable, EventHandler, Closeable{
private final EventHandler evt;
private final List<ClientHandler> clientes;
private final PrintWriter pw;
private ServerSocket serverSocket;
private Thread thread;
private boolean started;
public Server (PrintWriter writer, EventHandler evt) {
this.pw = writer;
this.evt = evt != null?evt:this;
this.clientes = new LinkedList<>();
}
public Server(){
this(new PrintWriter(System.out), null);
}
public boolean hasStarted(){
return started;
}
public synchronized void openServer(int port) throws IOException{
if(started) return;
pw.println("Iniciando servidor...");
serverSocket = new ServerSocket(port);
thread = new Thread(this);
thread.start();
started = true;
pw.println("Servidor iniciado na porta "+ port);
}
@Override
public synchronized void close() throws IOException{
if(!started) return;
pw.println("Interrompendo servidor...");
serverSocket.close();
closeClients();
started = false;
pw.println("Servidor parado");
evt.warning("Servidor Parado", "O servidor foi interrompido.");
}
public void closeClients(){
synchronized(clientes){
for(Iterator<ClientHandler> it = clientes.iterator(); it.hasNext();){
ClientHandler ch = it.next();
try {
ch.close();
it.remove();
} catch (IOException ex) {
pw.println("Erro ao fechar cliente: "+ch.getHostName());
pw.println(ex);
}
}
}
}
@Override
public void run() {
while (!serverSocket.isClosed()) {
try {
Socket cliente = serverSocket.accept();
//clientes.add(cliente);
pw.println("Nova conexão com o cliente " + cliente.getInetAddress().getHostAddress());
evt.notify("Cliente Conectado","Nova conexão com o cliente " + cliente.getInetAddress().getHostAddress());
ClientHandler c = new ClientHandler(cliente, pw);
clientes.add(c);
c.start();
} catch (IOException ex) {
pw.println(ex);
}
}
}
@Override
public void notify(String title, String message) {
String s = new StringBuilder("[Notify] ")
.append(title)
.append(": ")
.append(message)
.toString();
pw.println(s);
}
@Override
public void warning(String title, String message) {
String s = new StringBuilder("[Warning] ")
.append(title)
.append(": ")
.append(message)
.toString();
pw.println(s);
}
private static class ClientHandler extends Thread implements Closeable{
private final InputStream in;
private final PrintWriter pw;
private final Socket client;
public ClientHandler(Socket client, PrintWriter pw) throws IOException {
this.client = client;
this.in = client.getInputStream();
this.pw = pw;
}
public String getHostName(){
return client.getInetAddress().getHostAddress();
}
@Override
public void close() throws IOException{
client.close();
}
@Override
public void run() {
try (BufferedReader br = new BufferedReader(new InputStreamReader(in,Main.CHARSET))){
String s;
while ((s = br.readLine()) != null) {
pw.println(s);
}
} catch (IOException ex) {
System.err.println(ex);
pw.println(ex);
}
System.err.println("Thread Finalizada");
}
}
}