Una ayudita

kraneok

Hola, de nuevo por aquí exponiendo mis problemas.

Resulta que estoy desarrollando un chat en Java, en arquitectura Cliente/Servidor.
Bien, de momento el Cliente solo se dedica a enviar un Nick, introducido desde un jTextField y si es aceptado por el servidor, entra a a los hilos que le permite recibir y enviar información desde/hasta el servidor.

El servidor, como es normal, es mucho mas complejo, este recibe el Nick del cliente en cuestión, comprueba que no existe ese Nick ya en chat ( si está le envía una notificación al cliente ) por lo que al cliente se le obliga a elegir otro Nick, en caso de que no exista, se introduce en una Collection donde estarán todos los objetos con sus respectivos Nick y además se les adjunta el Socket que se ha generado.

Bien, mi problema es el siguiente:

Para recibir flujos de todos los clientes conectados lo que hago es lo siguiente.

Tengo una clase que hereda de Thread, y en su constructor se pasa la Collection de Clientes.
Pues dentro de este run existe un bucle while que recorre la Collection, saca el Cliente, saca el Socket del Cliente e intenta obtener el InputStream del Socket del Cliente, pero no se que pasa que no funciona.
Os pego el código y a ver si me arrojáis algo de luz o, si alguien ha creado un chat alguna vez me puede indicar como lo hizo el, este chat lo estoy haciendo por que yo quiero, para aprender algunas cosillas mas, etc.

 @Override
    public void run()
    {
        String dReceive = "";
        
while(sr.getStateServer()) { for(Client c: al) { try { Socket s = c.getSocket(); ois = new ObjectInputStream( s.getInputStream() ); dReceive = (String) ois.readObject(); System.out.println(dReceive); } catch (ClassNotFoundException ex) { ex.printStackTrace(); } catch (IOException ex) { ex.printStackTrace(); } } } }

Un saludo y gracias.

kraneok

Refloto para ver si alguien me puede echar una manita, gracias! =)

Wasd

No creo que sea la razón del error, pero yo ese "Socket s" de la línea 11 lo declararía fuera de los bucles.

1 respuesta
kraneok

#3 He hecho unas pruebas, y es en esta linea donde se queda parado todo:

ois = new ObjectInputStream( s.getInputStream() );
1 respuesta
Spacelord

#4 ¿Te da una traza del error? ¿O te dice al menos qué tipo de error es (nullpointer, etc)?

1 respuesta
kraneok

#5 No suelta ningún error, se queda pillado ahí, lo raro es que, si desconecto el cliente entonces me lanza un Connection reset, por lo que el cliente está conectado xD, es raro xd.

LOc0

A la clase que hereda de thread sólo deberías enviarle UN cliente.

A ver, la idea es bastante sencilla:

puede_tener_erratas

Eso en cuanto al SERVIDOR. En este caso a cada hilo se le manda sólo el socket, pero puedes enviarle un objeto de tipo Cliente con todo lo que quieras.

Salu2 ;)

1 respuesta
kraneok

#7 Muchas gracias, lo que has expuesto me ha aclarado bastante, aunque debo decir que es así como lo tenía antes.

La razón de por qué lo tengo ahora así, es sencilla, pensé que crear un hilo para cada cliente iba a ser pesado para el servidor ( y lo es ), entonces dije, pues ya está creo una clase que se llama ReceiverDara extends Thread, a este, le paso la Collection de clientes y entonces, con un solo hilo intentar gestionar todos los Socket, pero por lo que se ve, no funciona.

Lo de la Collection lo puedes ver arriba, Saco el Cliente de la Collection, saco del Cliente su Socket y del Socket saco el flujo de entrada, leo y mando por tubería al hilo encargado de enviar el texto a todos los clientes.

1 respuesta
storm2211

#8 para controlar todo el servidor con un solo hilo, hechale un vistazo a NIO y el uso de selectores.

elkaoD

Sube el código a algún lado y le echamos un vistazo, porque en el otro hilo lo que ponías tenía sentido.

1 respuesta
kraneok

#10

¿ Esto te vale ?
Dime si no, lo que te hace falta.
Gracias

 public void run()
    {
        try {
            String dReceive = "";
            Socket s        = null;
            
while( sr.getStateServer() ) { for( Client c: al ) { try { s = c.getSocket(); //Se queda ois = new ObjectInputStream( s.getInputStream() ); dReceive = ( String ) ois.readObject(); System.out.println( dReceive ); } catch (ClassNotFoundException ex) { ex.printStackTrace(); } catch (IOException ex) { ex.printStackTrace(); } } } s.close(); ois.close(); } catch (IOException ex) { Logger.getLogger(ReceiverData.class.getName()).log(Level.SEVERE, null, ex); } }
1 respuesta
elkaoD

#11 tienes el concepto al revés, ¡esto no es como lo tenías antes!

No puedes recibir en cada hilo de TODOS los clientes sino que cada cliente debe ser un hilo (si vas a usar sockets bloqueantes.) Si lo haces como ahora, los clientes deberán hablar de uno en uno y en orden para que el for tire hacia delante.

El InputStream sólo necesitas uno, no hacer el get en cada vuelta del while. En cada vuelta sí debes hacer readObject sobre EL MISMO InputStream.

Cuando recibas algo del InputStream se lo debes remitir al consumidor que supongo en este caso simplemente escribirá sobre el OutputStream de cada socket.

1 respuesta
kraneok

#12 Bien, pues entonces lo dejo como estaba.
Creo una clase a la que se le pase el Socket cliente e implemente Thread.

Realmente esta forma de intentar hacerlo surgió por que vi que los hilos consumen muchísima máquina y se realentiza, pero si no hay otra forma..xD, de todos modos es de prueba para aprender cosillas y tal, así que np.

Cuando recibas algo del InputStream se lo debes remitir al consumidor que supongo en este caso simplemente escribirá sobre el OutputStream de cada socket.

Si, así es exactamente, en el caso del Consumidor que reparte lo obtenido, si se puede hacer así sin problemas, "creo" xD.

Usuarios habituales

  • kraneok
  • elkaoD
  • storm2211
  • LOc0
  • Spacelord
  • Wasd