Sobre hilos

Aquí estamos de nuevo.
Se me ha presentado un problema que no sé cómo solucionar.
Te explico.
Tengo la clase1 que abre un hilo para ejecutar clase2.
La clase 1 puede terminar de 2 formas distintas. O bien manualmente el usuario pulsa un botón o bien desde clase2 automáticamente.
La clase2 escucha por un puerto y si le llega cierto mensaje pues cierra clase1, y se acaba clase2.
El problema viene cuando se cierra clase1 manualmente. Clase 2 al ser un hilo sigue en ejecución. Cuando vuelva a ejecutarse clase1 abre de nuevo un hilo para clase2 y da error de socket porque el puerto ya está abierto, ya que clase1 se quedó en ejecución anteriormente.
¿Cómo puedo acabar con clase2 cuando se cierre manualmente clase1?.
Espero haberme explicado bien.

1 respuesta

Respuesta
1
Te he entendido. Lo que yo haría es tener un método en Clase2 que se llame abortar() o algo así. Este abortar() lo que debería hacer es dos cosas: activar una variable de control que se llame abortar y cerrar el socket. El método run() de Clase2 imagino que tendrá un bucle infinito. En él, deberás comprobar antes del serverSocket. Accept() si la variable "abortar" está activa, para finalizar el bucle. También es muy importante que todo el método del run esté en un try-catch Exception, porque al cerrar el socket desde fuera, la excepción saltará. Entonces, en la siguiente iteración del bucle, se comprobará la variable de control "abortar", y como será true, pues se saldrá del bucle, quedando el hilo finalizado.
Espero que te sirva. Si tienes dudas, ya sabes.
Sí, pero falta lo más importante. ¿Cómo sé cuándo debo abortar?. Cuando le llega el mensaje a Clase2 no hay problema porque se cierra bien, pero cuando Clase1 se cierra, ¿cómo se entera Clase2 para abortarse?.
Pues si la clase es un JFrame, captura el evento de cerrado.
Uf, no veas lo que me está costando. Nada. No hay forma que de se cierre bien el socket.
Mira a ver qué estoy haciendo mal.
Te dejo el código.
*************************************************************
class EscuchaCierreSesion implements Runnable {
ServerSocket ss=null; // Socket por el que espera peticiones del cliente
Socket s=null; // Socket para la comunicación con el cliente
PrintWriter os=null;
// Canal de salida para el envio de datos por el socket
BufferedReader is=null;
//Canal de entrada para la lectura de datos por el socket
Integer Error=0;
char Estado='B';
int salir=0;
iTop Top;
Reloj reloj;
int abortar = 0;
public EscuchaCierreSesion(final iTop Top, final Reloj reloj){ //Constructor
this.Top = Top;
this.reloj= reloj;
this.reloj.cerrar.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e){ System.out.println("Se salió del reloj y salgo");
abortar(); }
});
}
public void run() {
try{
System.out.println("A la espera de petición en Escucha CierreSesion");
ss=new ServerSocket(1314,300);
while (true) {
try{ //System.out.println(this.Top.getEstado());
if (abortar==1) {
System.out.println("salgo de Escucha cierreSesion");
// os.close(); // Cerramos canal de salida
// is.close(); // Cerramos canal de entrada
break;
}
s=ss.accept(); // espera a la petición de un cliente
// Obtenemos los canales del socket que establece la
// comunicación entre cliente y servidor.
is=new BufferedReader(
new InputStreamReader(
s.getInputStream()));
// Obtenemos un canal de entrada (lectura) del socket
// Aplicamos estratos para poder leer tipos primitivos
// y utilizamos un buffer para la lectura
os=new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
s.getOutputStream())),true);
//Obtenemos un canal de salida (escritura) del socket
//Utilizamos un buffer para la lectura y escribiremos texto
//Capturamos las excepciones que puede lanzar el código
}
catch(IOException e){ System.out.println("Error de E/S en la conexión\n"); Error=1;}
if (Error==0 && s!=null && is!=null && os!=null){
try{
String mensaje="";
String codigo="";
while (true) {
mensaje=is.readLine();
if (mensaje!=null) {
for (int i=0; i<mensaje.length(); i++) codigo = codigo + mensaje.charAt(i);
System.out.println("Codigo recibigo: + codigo\n");
if (codigo.indexOf("fin") == 0) new AvisoFin();
else if (codigo.indexOf("close") == 0) { //new CierraSesion(this.Top);
this.reloj.Acaba();
System.out.println("Voy a salir del bucle de escuchar mensajes en Escucha cierre sesión");
salir=1; break;}
}
else break;
}
}
catch (IOException e){ System.out.println("Error de E/S en la conexión \n"); }
}
//}
if (salir==1){
System.out.println("Salgo del bucle de Escucha cierre sesión");
break;
}
} // while(true)
System.out.println("Salgo del try de escucha cierre sesión");
} // try
catch (IOException e){ System.out.println("Error de E/S en la conexión en Escucha Cierre Sesión\n");}
}
public void abortar(){
abortar=1;
try{
s.close();
salir=1;
System.out.println("Acabo de cerrar sockets");
}
catch(IOException i){ System.out.println("Error de E/S en la conexión\n"); }
}
}
A mí este código me funciona:
import java.net.*;
import java.io.*;
public class EscuchadorSocket implements Runnable{
private boolean abortar = false;
private ServerSocket ss;
public EscuchadorSocket(){
   try {
      ss = new ServerSocket(40000);
   } catch (IOException e) {
       e.printStackTrace();
   }
   Thread t = new Thread (this);
    t.start();
}
public void run(){
    while (!abortar){
       try {
          Socket s = ss.accept();
       } catch (IOException e) {
          System.out.println("Excepcion en el accept()");
           e.printStackTrace();
       }
    }
    System.out.println("Fin del run()");
}
public void abortar(){
   System.out.println("abortar(): Cierro socket");
   this.abortar = true;
   try {
       ss.close();
   } catch (IOException e) {
        e.printStackTrace();
   }
}
}
Comprueba que Clase1 esté llamando a clase2. Abortar() al cerrarse.
Vale, creo que te entendí mal.
Tu lo que dices es que cuando Clase1 cierre manualmente, llame al método clase2. Abortar() para que se cierre.
Bueno, vamos a probarlo.
En la llamada desde clase1 tengo:
new Thread ( new EscuchaCierreSesion(this.referenciaATop,referencia()) , "").start();
Cómo hago referencia a EscuchaCierreSesion. ¿Abortar() desde clase1?
Lo primero es que en Clase1 tienes que declarar una variable del tipo:
private EscuchaCierreSesion ecs;
Luego, desglosa tu código en esto:
ecs = new EscuchaCierreSesion(this.referenciaATop,referencia());
new Thread ( ecs, "").start();
Y finalmente, cuando detectes que Clase1 se cierra, llama a ecs.abortar();

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas