Problem when capturing SocketException

1

Hi, I am trying to implement a group chat in Java. The chat is fully functional, (the basics). My intention is to capture when a user disconnects to be able to delete their name from the arrayList of the users of the server, but I can not identify when it is disconnected. I have placed a try / catch on my server to capture the SocketException , but it never enters there.

My code for my server is as follows:

    import java.io.IOException;
    import java.io.PrintWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.net.SocketException;
    import java.util.ArrayList;

public class ServerChat {

    static ArrayList<String> usuarios = new ArrayList<String>();

    static ArrayList<PrintWriter> printWriters = new ArrayList<PrintWriter>();

    public ServerChat() {
        usuarios = null;
        printWriters = null;

    }

    public static void main(String[] args) throws SocketException {

        try {

            System.out.println("Esperando por peticiones de clientes... ");
            ServerSocket ss = new ServerSocket(9001);


            while (true) {
                try {
                    Socket soc = ss.accept(); // representa al cliente
                    System.out.println("Cliente conectado. ");

                    ManejadorConver manejador = new ManejadorConver(soc, usuarios.size());
                    manejador.start();
                } catch (SocketException e) {
                    System.out.println("Se ha desconectado un cliente");
                }

            }

        } catch (IOException e) {
            e.printStackTrace();

        }
    }

}

Client Code:

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class ClienteChat {

    static JFrame ventanaChat = new JFrame("Aplicación Chat CS");
    static JTextArea areaChat = new JTextArea(22, 40); // (filas, columnas)
    static JTextField campoTexto = new JTextField(40);
    static JLabel espacioBlanco = new JLabel("      ");
    static JButton botonEnvio = new JButton("Enviar");
    static JLabel nombreSesion = new JLabel("       ");

    static BufferedReader entrada;
    static PrintWriter salida;

    public ClienteChat() {

        ventanaChat.setLayout(new FlowLayout());
        ventanaChat.add(nombreSesion);
        ventanaChat.add(new JScrollPane(areaChat));
        ventanaChat.add(espacioBlanco);
        ventanaChat.add(campoTexto);
        ventanaChat.add(botonEnvio);

        ventanaChat.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        ventanaChat.setSize(475, 500); 
        ventanaChat.setVisible(true); 

        campoTexto.setEditable(false); 
        areaChat.setEditable(false);
        botonEnvio.addActionListener(new Listener());
        campoTexto.addActionListener(new Listener());

    }

    public void encenderCliente() throws Exception {

        String dirIP = JOptionPane.showInputDialog(ventanaChat, "Introduce dirección IP:", "Direcci�n IP requerida",
                JOptionPane.PLAIN_MESSAGE);

        Socket socket = new Socket(dirIP, 9001);
        entrada = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        salida = new PrintWriter(socket.getOutputStream(), true);

        while (true) {

            String str = entrada.readLine();
            String nombre = null;

             if (str.equals("NOMBRENECESARIO")) {

                nombre = JOptionPane.showInputDialog(ventanaChat, "Introduce un nickname único:",
                        "Nickname requerido", JOptionPane.PLAIN_MESSAGE);

                salida.println(nombre);

            } else if (str.equals("NOMBREPREEXISTENTE")) {

                nombre = JOptionPane.showInputDialog(ventanaChat, "Introduce otro nickname:", "Este nickname ya existe",
                        JOptionPane.WARNING_MESSAGE);

                salida.println(nombre);

            } else if (str.startsWith("NOMBREACEPTADO")) {

                campoTexto.setEditable(true); 
                nombreSesion.setText("Has hecho login con el nombre: " + str.substring(14));

            } else {

                areaChat.append(str + "\n");

            }    

        }

    }

    class Listener implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            String texto = ClienteChat.campoTexto.getText();

            ClienteChat.salida.println(texto);
            ClienteChat.campoTexto.setText("");

        }
    }

    public static void main(String[] args) throws Exception {
        ClienteChat cliente = new ClienteChat();
        cliente.encenderCliente();
    }

}

Handler Code:

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

public class ManejadorConver extends Thread {

    Socket socket;
    BufferedReader entrada;
    PrintWriter salida;
    String nombre;

    public ManejadorConver(Socket socket) throws IOException {
        this.socket = socket;
    }

    public void run() {

        try {

            int i = 0;
            entrada = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            salida = new PrintWriter(socket.getOutputStream(), true);

            while (true) {


                if (i > 0) {
                    salida.println("NOMBREPREEXISTENTE");
                } else {
                    salida.println("NOMBRENECESARIO");
                }

                nombre = entrada.readLine();

                if (nombre == null) {
                    return;
                }

                if (!ServerChat.usuarios.contains(nombre)) {

                    ServerChat.usuarios.add(nombre);
                    break;
                }

                i++;

            }

            salida.println("NOMBREACEPTADO" + nombre);
            ServerChat.printWriters.add(salida);

            while (true) {
                String mensaje = entrada.readLine();

                if (mensaje == null) {
                    return;
                }

                for (PrintWriter writer : ServerChat.printWriters) {

                    writer.println(nombre + ": " + mensaje);

                }
            }

        } catch (Exception e) {

            System.out.println(e);

        }

    }
}

PROBLEM : it never enters that try-catch and I can not catch the disconnection.

The console shows me this when I close a client's window:

  

Waiting for customer requests ... Client connected. java.net.SocketException: Connection reset.

... but it does not enter that try catch that I put on the server to capture just that Exception .

Could someone help me out? Thank you very much.

    
asked by owenjr 04.12.2017 в 22:45
source

1 answer

0

The problem is that the exception SocketException is thrown from a thread different from the main .

When you accept a client connection in main , the instance of the socket is passed to the instance of class ManejadorConver , which runs in a different thread:

ManejadorConver manejador = new ManejadorConver(soc, usuarios.size());
manejador.start(); // <-- esto corre en otro hilo

Any exception that arises while running manejador.start() will not catch you in main() .

Rather, the place where you should handle the SocketException is in the ManejadorConver.run() method. And in fact, there you already have a try-catch that does the following and that explains the message you receive in the console:

   } catch (Exception e) {

        System.out.println(e);

    }

It is in that place that you must add an exception handler to handle the disconnection of the client.

Example:

} catch (SocketException e) {
    System.out.println("Se ha desconectado un cliente");
} catch (Exception e) {
    System.out.println(e);
}

... although take into account that a SocketException can occur for several reasons, and not all of them imply that the client was disconnected. Something to take into account.

    
answered by 04.12.2017 / 23:03
source