Chat Java con Eclipse

33
[código] Conexiones Cliente-Servidor mediante sockets en Java 3 tweets retweet Por falta de tiempo me es imposible explicar este código detalladamente, tal como me gustaría, pero no tengo otra opción que simplemente ponerlo. Aún así es de recordar que pueden dejar todos los comentarios que deseen, con sus dudas y sugerencias ( que no pedidos de tareas ). Aún así explico un poco el resultado del programa el programa es un chat simple (muy simple), que usa Sockets para crear conexiones de red. Consta de un servidor (Servidor.java) y un cliente (Cliente.java), mediante los cuales se puede establecer una conversación. Si se escribe “TERMINAR” (sin comillas), la conexión se cierra. El resultado

description

Chat creado con Soker

Transcript of Chat Java con Eclipse

Page 1: Chat Java con Eclipse

[código] Conexiones Cliente-Servidor mediante sockets en Java3 tweets  retweet

Por falta de tiempo me es imposible explicar este código detalladamente, tal como me gustaría, pero no

tengo otra opción que simplemente ponerlo. Aún así es de recordar que pueden dejar todos los

comentarios que deseen, con sus dudas y sugerencias (que no pedidos de tareas).

Aún así explico un poco el resultado del programa… el programa es un chat simple (muy simple), que

usa Sockets para crear conexiones de red. Consta de un servidor (Servidor.java) y un cliente

(Cliente.java), mediante los cuales se puede establecer una conversación. Si se escribe “TERMINAR” (sin

comillas), la conexión se cierra.

El resultado

 

 

Page 2: Chat Java con Eclipse

El código

El código fuente de Servidor.java:

001002003004005006007008009010011012013014015016017018019020021022023024025026027

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

public class Servidor extends JFrame {   private JTextField campoIntroducir;   private JTextArea areaPantalla;   private ObjectOutputStream salida;   private ObjectInputStream entrada;   private ServerSocket servidor;   private Socket conexion;   private int contador = 1;

   // configurar GUI   public Servidor()   {      super( "Servidor" );

      Container contenedor = getContentPane();

      // crear campoIntroducir y registrar componente de escucha      campoIntroducir = new JTextField();      campoIntroducir.setEditable( false );      campoIntroducir.addActionListener(         new ActionListener() {

            // enviar mensaje al cliente

Page 3: Chat Java con Eclipse

028029030031032033034035036037038039040041042043044045046047048049050051052053054055056057058059060061062063064065066067068069070071072073074

            public void actionPerformed( ActionEvent evento )            {               enviarDatos( evento.getActionCommand() );               campoIntroducir.setText( "" );            }         }      );

      contenedor.add( campoIntroducir, BorderLayout.NORTH );

      // crear areaPantalla      areaPantalla = new JTextArea();      contenedor.add( new JScrollPane( areaPantalla ),         BorderLayout.CENTER );

      setSize( 300, 150 );      setVisible( true );

   } // fin del constructor de Servidor

   // configurar y ejecutar el servidor   public void ejecutarServidor()   {      // configurar servidor para que reciba conexiones; procesar las conexiones      try {

         // Paso 1: crear un objeto ServerSocket.         servidor = new ServerSocket( 12345, 100 );

         while ( true ) {

            try {               esperarConexion(); // Paso 2: esperar una conexión.               obtenerFlujos();        // Paso 3: obtener flujos de entrada y salida.               procesarConexion(); // Paso 4: procesar la conexión.            }

            // procesar excepción EOFException cuando el cliente cierre la conexión            catch ( EOFException excepcionEOF ) {               System.err.println( "El servidor terminó la conexión" );            }

            finally {               cerrarConexion();   // Paso 5: cerrar la conexión.               ++contador;            }

         } // fin de instrucción while

      } // fin del bloque try

Page 4: Chat Java con Eclipse

075076077078079080081082083084085086087088089090091092093094095096097098099100101102103104105106107108109110111112113114115116117118119120121

      // procesar problemas con E/S      catch ( IOException excepcionES ) {         excepcionES.printStackTrace();      }

   } // fin del método ejecutarServidor

   // esperar que la conexión llegue, después mostrar información de la conexión   private void esperarConexion() throws IOException   {      mostrarMensaje( "Esperando una conexión\n" );      conexion = servidor.accept(); // permitir al servidor aceptar la conexión      mostrarMensaje( "Conexión " + contador + " recibida de: " +         conexion.getInetAddress().getHostName() );   }

   // obtener flujos para enviar y recibir datos   private void obtenerFlujos() throws IOException   {      // establecer flujo de salida para los objetos      salida = new ObjectOutputStream( conexion.getOutputStream() );      salida.flush(); // vaciar búfer de salida para enviar información de encabezado

      // establecer flujo de entrada para los objetos      entrada = new ObjectInputStream( conexion.getInputStream() );

      mostrarMensaje( "\nSe recibieron los flujos de E/S\n" );   }

   // procesar la conexión con el cliente   private void procesarConexion() throws IOException   {      // enviar mensaje de conexión exitosa al cliente      String mensaje = "Conexión exitosa";      enviarDatos( mensaje );

      // habilitar campoIntroducir para que el usuario del servidor pueda enviar mensajes      establecerCampoTextoEditable( true );

      do { // procesar los mensajes enviados por el cliente

         // leer el mensaje y mostrarlo en pantalla         try {            mensaje = ( String ) entrada.readObject();            mostrarMensaje( "\n" + mensaje );         }

         // atrapar problemas que pueden ocurrir al tratar de leer del cliente         catch ( ClassNotFoundException excepcionClaseNoEncontrada ) {            mostrarMensaje( "\nSe recibió un tipo de objeto desconocido" );         }

Page 5: Chat Java con Eclipse

122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168

      } while ( !mensaje.equals( "CLIENTE>>> TERMINAR" ) );

   } // fin del método procesarConexion

   // cerrar flujos y socket   private void cerrarConexion()   {      mostrarMensaje( "\nFinalizando la conexión\n" );      establecerCampoTextoEditable( false ); // deshabilitar campoIntroducir

      try {         salida.close();         entrada.close();         conexion.close();      }      catch( IOException excepcionES ) {         excepcionES.printStackTrace();      }   }

   // enviar mensaje al cliente   private void enviarDatos( String mensaje )   {      // enviar objeto al cliente      try {         salida.writeObject( "SERVIDOR>>> " + mensaje );         salida.flush();         mostrarMensaje( "\nSERVIDOR>>> " + mensaje );      }

      // procesar problemas que pueden ocurrir al enviar el objeto      catch ( IOException excepcionES ) {         areaPantalla.append( "\nError al escribir objeto" );      }   }

   // método utilitario que es llamado desde otros subprocesos para manipular a   // areaPantalla en el subproceso despachador de eventos   private void mostrarMensaje( final String mensajeAMostrar )   {      // mostrar mensaje del subproceso de ejecución despachador de eventos      SwingUtilities.invokeLater(         new Runnable() {  // clase interna para asegurar que la GUI se actualice apropiadamente

            public void run() // actualiza areaPantalla            {               areaPantalla.append( mensajeAMostrar );               areaPantalla.setCaretPosition(                  areaPantalla.getText().length() );            }

Page 6: Chat Java con Eclipse

169170171172173174175176177178179180181182183184185186

         }  // fin de la clase interna

      ); // fin de la llamada a SwingUtilities.invokeLater   }

   // método utilitario que es llamado desde otros subprocesos para manipular a   // campoIntroducir en el subproceso despachador de eventos   private void establecerCampoTextoEditable( final boolean editable )   {      // mostrar mensaje del subproceso de ejecución despachador de eventos      SwingUtilities.invokeLater(         new Runnable() {  // clase interna para asegurar que la GUI se actualice apropiadamente

            public void run()  // establece la capacidad de modificar a campoIntroducir            {               campoIntroducir.setEditable( editable );            }

         }  // fin de la clase interna

      ); // fin de la llamada a SwingUtilities.invokeLater   }

   public static void main( String args[] )   {      JFrame.setDefaultLookAndFeelDecorated(true);      Servidor aplicacion = new Servidor();      aplicacion.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );      aplicacion.ejecutarServidor();   }

}  // fin de la clase Servidor

El código fuente de Cliente.java:

?001002003004005006007008009010011

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

public class Cliente extends JFrame {   private JTextField campoIntroducir;   private JTextArea areaPantalla;   private ObjectOutputStream salida;   private ObjectInputStream entrada;   private String mensaje = "";

Page 7: Chat Java con Eclipse

012013014015016017018019020021022023024025026027028029030031032033034035036037038039040041042043044045046047048049050051052053054055056057058

   private String servidorChat;   private Socket cliente;

   // inicializar servidorChat y configurar GUI   public Cliente( String host )   {      super( "Cliente" );

      servidorChat = host; // establecer el servidor al que se va a conectar este cliente

      Container contenedor = getContentPane();

      // crear campoIntroducir y registrar componente de escucha      campoIntroducir = new JTextField();      campoIntroducir.setEditable( false );      campoIntroducir.addActionListener(         new ActionListener() {

            // enviar mensaje al servidor            public void actionPerformed( ActionEvent evento )            {               enviarDatos( evento.getActionCommand() );               campoIntroducir.setText( "" );            }         }      );

      contenedor.add( campoIntroducir, BorderLayout.NORTH );

      // crear areaPantalla      areaPantalla = new JTextArea();      contenedor.add( new JScrollPane( areaPantalla ),         BorderLayout.CENTER );

      setSize( 300, 150 );      setVisible( true );

   } // fin del constructor de Cliente

   // conectarse al servidor y procesar mensajes del servidor   private void ejecutarCliente()   {      // conectarse al servidor, obtener flujos, procesar la conexión      try {         conectarAServidor(); // Paso 1: crear un socket para realizar la conexión         obtenerFlujos();      // Paso 2: obtener los flujos de entrada y salida         procesarConexion(); // Paso 3: procesar la conexión      }

      // el servidor cerró la conexión      catch ( EOFException excepcionEOF ) {

Page 8: Chat Java con Eclipse

059060061062063064065066067068069070071072073074075076077078079080081082083084085086087088089090091092093094095096097098099100101102103104105

         System.err.println( "El cliente termino la conexión" );      }

      // procesar los problemas que pueden ocurrir al comunicarse con el servidor      catch ( IOException excepcionES ) {         excepcionES.printStackTrace();      }

      finally {         cerrarConexion(); // Paso 4: cerrar la conexión      }

   } // fin del método ejecutarCliente

   // conectarse al servidor   private void conectarAServidor() throws IOException   {      mostrarMensaje( "Intentando realizar conexión\n" );

      // crear Socket para realizar la conexión con el servidor      cliente = new Socket( InetAddress.getByName( servidorChat ), 12345 );

      // mostrar la información de la conexión      mostrarMensaje( "Conectado a: " +         cliente.getInetAddress().getHostName() );   }

   // obtener flujos para enviar y recibir datos   private void obtenerFlujos() throws IOException   {      // establecer flujo de salida para los objetos      salida = new ObjectOutputStream( cliente.getOutputStream() );      salida.flush(); // vacíar búfer de salida para enviar información de encabezado

      // establecer flujo de entrada para los objetos      entrada = new ObjectInputStream( cliente.getInputStream() );

      mostrarMensaje( "\nSe recibieron los flujos de E/S\n" );   }

   // procesar la conexión con el servidor   private void procesarConexion() throws IOException   {      // habilitar campoIntroducir para que el usuario del cliente pueda enviar mensajes      establecerCampoTextoEditable( true );

      do { // procesar mensajes enviados del servidor

         // leer mensaje y mostrarlo en pantalla         try {            mensaje = ( String ) entrada.readObject();

Page 9: Chat Java con Eclipse

106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152

            mostrarMensaje( "\n" + mensaje );         }

         // atrapar los problemas que pueden ocurrir al leer del servidor         catch ( ClassNotFoundException excepcionClaseNoEncontrada ) {            mostrarMensaje( "\nSe recibió un objeto de tipo desconocido" );         }

      } while ( !mensaje.equals( "SERVIDOR>>> TERMINAR" ) );

   } // fin del método procesarConexion

   // cerrar flujos y socket   private void cerrarConexion()   {      mostrarMensaje( "\nCerrando conexión" );      establecerCampoTextoEditable( false ); // deshabilitar campoIntroducir

      try {         salida.close();         entrada.close();         cliente.close();      }      catch( IOException excepcionES ) {         excepcionES.printStackTrace();      }   }

   // enviar mensaje al servidor   private void enviarDatos( String mensaje )   {      // enviar objeto al servidor      try {         salida.writeObject( "CLIENTE>>> " + mensaje );         salida.flush();         mostrarMensaje( "\nCLIENTE>>> " + mensaje );      }

      // procesar los problemas que pueden ocurrir al enviar el objeto      catch ( IOException excepcionES ) {         areaPantalla.append( "\nError al escribir el objeto" );      }   }

   // método utilitario que es llamado desde otros subprocesos para manipular a   // areaPantalla en el subproceso despachador de eventos   private void mostrarMensaje( final String mensajeAMostrar )   {      // mostrar mensaje del subproceso de ejecución de la GUI      SwingUtilities.invokeLater(         new Runnable() {  // clase interna para asegurar que la GUI se actualice apropiadamente

Page 10: Chat Java con Eclipse

153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182

            public void run() // actualiza areaPantalla            {               areaPantalla.append( mensajeAMostrar );               areaPantalla.setCaretPosition(                  areaPantalla.getText().length() );            }

         }  // fin de la clase interna

      ); // fin de la llamada a SwingUtilities.invokeLater   }

   // método utilitario que es llamado desde otros subprocesos para manipular a   // campoIntroducir en el subproceso despachador de eventos   private void establecerCampoTextoEditable( final boolean editable )   {      // mostrar mensaje del subproceso de ejecución de la GUI      SwingUtilities.invokeLater(         new Runnable() {  // clase interna para asegurar que la GUI se actualice apropiadamente

            public void run()  // establece la capacidad de modificar campoIntroducir            {               campoIntroducir.setEditable( editable );            }

         }  // fin de la clase interna

      ); // fin de la llamada a SwingUtilities.invokeLater   }

   public static void main( String args[] )   {      JFrame.setDefaultLookAndFeelDecorated(true);      Cliente aplicacion;

      if ( args.length == 0 )         aplicacion = new Cliente( "127.0.0.1" );      else         aplicacion = new Cliente( args[ 0 ] );

      aplicacion.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );      aplicacion.ejecutarCliente();   }

} // fin de la clase Cliente

Page 11: Chat Java con Eclipse
Page 12: Chat Java con Eclipse
Page 13: Chat Java con Eclipse

Este es el codigo para el servidor:=================================import java.io.EOFException;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.net.ServerSocket;import java.net.Socket;import java.awt.BorderLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.JFrame;import javax.swing.JScrollPane;import javax.swing.JTextArea;import javax.swing.JTextField;import javax.swing.SwingUtilities;

Page 14: Chat Java con Eclipse

public class Servidor extends JFrame{private JTextField campoEscritura;private JTextArea areaCharla;private ObjectOutputStream salida;private ObjectInputStream entrada;private ServerSocket servicio;private Socket conexion;private int contador;

//Configuracion de GUIpublic Servidor(){super("Servidor");campoEscritura = new JTextField();campoEscritura.setEditable(false);campoEscritura.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){enviarDatos(e.getActionCommand());campoEscritura.setText("");}});

add(campoEscritura, BorderLayout.SOUTH);

areaCharla = new JTextArea();add(new JScrollPane(areaCharla), BorderLayout.CENTER);

setSize(300,150);setVisible(true);}

Page 15: Chat Java con Eclipse

public void iniciarServidor(){try{servicio = new ServerSocket(12345, 100);

while(true){try{esperarConexion();getFlujos();procesarConexion();}catch(EOFException eof){mostrarMensaje("Servidor termino la conexion");}finally{cerrarConexion();contador++;}}}catch(IOException io){io.printStackTrace();}}

private void esperarConexion() throws IOException{mostrarMensaje("Esperando Conexiones");conexion = servicio.accept();mostrarMensaje("Conección "+contador+" recibida de: "+ conexion.getInetAddress().getHostName());}

Page 16: Chat Java con Eclipse

private void getFlujos() throws IOException{salida = new ObjectOutputStream(conexion.getOutputStream());salida.flush();

entrada = new ObjectInputStream(conexion.getInputStream());mostrarMensaje("n Corren los Flujos de E/S n");}

private void procesarConexion() throws IOException{String mensaje = "Conexion Establecida";

enviarDatos(mensaje);

setTextFieldEditable(true);

do{try{mensaje = (String) entrada.readObject();mostrarMensaje("n"+mensaje);}catch(ClassNotFoundException cnfe){mostrarMensaje("n Tipo de Objeto desconocido fue recibido");}} while(!mensaje.equals("CLIENT>>> FINITO"));}

private void cerrarConexion(){mostrarMensaje("nConexión cerradan");setTextFieldEditable(false);

try{salida.close();entrada.close();

Page 17: Chat Java con Eclipse

conexion.close();} catch(IOException io){io.printStackTrace();}}

private void enviarDatos(String mensaje){try{salida.writeObject("nSERVER>>> "+mensaje);salida.flush();mostrarMensaje("nSERVER>>> "+ mensaje);}catch(IOException io){areaCharla.append("nError al escribir el objeto");}}

private void mostrarMensaje(final String mensajeAmostrar){SwingUtilities.invokeLater(new Runnable(){public void run(){areaCharla.append(mensajeAmostrar);}});}

private void setTextFieldEditable(final boolean editable){SwingUtilities.invokeLater(new Runnable(){

Page 18: Chat Java con Eclipse

public void run(){campoEscritura.setEditable(editable);}});}}

este el codigo para probar el Servidor:========================================import javax.swing.JFrame;

public class PruebaServidor{public static void main( String args[] ){Servidor servidor = new Servidor(); // create serverservidor.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );servidor.iniciarServidor(); // run server application} // end main}

Este el codigo para un Cliente para el chat===========================================import java.io.EOFException;

Page 19: Chat Java con Eclipse

import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.net.InetAddress;import java.net.Socket;import java.awt.BorderLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.JFrame;import javax.swing.JScrollPane;import javax.swing.JTextArea;import javax.swing.JTextField;import javax.swing.SwingUtilities;

public class Cliente extends JFrame{private JTextField campoTexto;private JTextArea areaCharla;private ObjectOutputStream output;private ObjectInputStream input;private String mensaje = "";private String ipServidor;private Socket cliente;

public Cliente( String host ){

super( "Cliente" );

ipServidor = host;campoTexto = new JTextField();campoTexto.setEditable( false );campoTexto.addActionListener(

Page 20: Chat Java con Eclipse

new ActionListener(){public void actionPerformed( ActionEvent event ){enviarDatos( event.getActionCommand() );campoTexto.setText( "" );}});

add( campoTexto, BorderLayout.SOUTH );

areaCharla = new JTextArea();add( new JScrollPane( areaCharla ), BorderLayout.CENTER );setSize( 300, 150 );setVisible( true );}

public void correrCliente(){try{conectarAservidor();conseguirFlujo();procesarConexion();}catch ( EOFException eofException ) {mostrarMensaje( "nClient terminated connection" );}catch ( IOException ioException ){ioException.printStackTrace();}finally {cerrarConexion();}}

Page 21: Chat Java con Eclipse

private void conectarAservidor() throws IOException{mostrarMensaje( "Esperando conectarse" );

cliente = new Socket( InetAddress.getByName( ipServidor ), 12346 );

mostrarMensaje( "Connected to: " + cliente.getInetAddress().getHostName() );}

private void conseguirFlujo() throws IOException {output = new ObjectOutputStream( cliente.getOutputStream() );output.flush();input = new ObjectInputStream( cliente.getInputStream() );mostrarMensaje( "nExiste conexion con Servidorn" );}

private void procesarConexion() throws IOException{setTextFieldEditable( true );do{try{mensaje = ( String ) input.readObject();mostrarMensaje( "n" + mensaje );}catch ( ClassNotFoundException classNotFoundException ){mostrarMensaje( "nUnknown object type received" );}

} while ( !mensaje.equals( "SERVER>>> FINITO" ) );}

private void cerrarConexion(){mostrarMensaje( "nCerrando la conexion" );setTextFieldEditable( false );

Page 22: Chat Java con Eclipse

try{output.close();input.close();cliente.close();}catch ( IOException ioException ){ioException.printStackTrace();}}

private void enviarDatos( String sms ){try{output.writeObject( "CLIENTE>>> " + sms );output.flush();mostrarMensaje( "nCLIENTE>>> " + sms );}catch ( IOException ioException ){areaCharla.append( "nNo se puede enviar el mensaje" );}}

private void mostrarMensaje( final String mensajeToDisplay ) {//SwingUtilities.invokeLater(// new Runnable()//{// public void run()//{areaCharla.append( mensajeToDisplay );

Page 23: Chat Java con Eclipse

//}//}//);}

private void setTextFieldEditable( final boolean editable ){SwingUtilities.invokeLater(new Runnable(){public void run() // sets campoTexto’s editability{campoTexto.setEditable( editable );}});}}

Este el codigo para ejecutar Cliente, recuerda que se hace uso de tu servidor interno LOCALHOST 127.0.0.1===========================================import javax.swing.JFrame;public class ClientTest {public static void main( String args[] ) {Cliente cliente;cliente = new Cliente( "127.0.0.1" );

Page 24: Chat Java con Eclipse

cliente.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );cliente.correrCliente();}}

Para probar esto, es importante que primero ejecutes el Servidor, esto se debe a que se esta usando TCP,

OTROOO

Sockets java. Atender varios clientes con hilos. Un chat de ejemplo.

En este tutorial vamos a ver cómo un servidor de socket puede atender a la vez a varios clientes creando un hilo con cada uno de ellos. Como la idea es simple y se explica en dos patadas, haremos un ejemplo algo más complejo: un chat capaz de atender varios clientes a la vez.

El código del chat puedes bajártelo y probarlo al final. Tampoco es un chat muy elaborado, puesto que sólo se pretende dar una idea de cómo atender a varios

Page 25: Chat Java con Eclipse

clientes con hilos. Tampoco me he preocupado de hacerlo robusto, así que si le das caña es posible que tengas algún problema

LA IDEA BÁSICA PARA EL SERVIDOR

Como he comentado arriba, la idea es muy sencilla. Basta con hacerse una clase susceptible de ser lanzada en un hilo aparte para atender a cada cliente. El servidorúnicamente debe meterse en un bucle infinito a la espera de un cliente y cuando llegue, instanciar una clase de estas y lanzar el hilo.

La clase para el hilo encargada de atender a cada cliente puede ser algo parecido a esto

HiloDeCliente.java

// Implementa Runnable para poder ser lanzada en un hilo apartepublic class HiloDeCliente implements Runnable{ // En el constructor recibe y guarda los parámetros que sean necesarios. // En este caso una lista con toda la conversación y el socket que debe // atender. public HiloDeCliente(DefaultListModel charla, Socket socket) { ... }

public void run () { while (true) { // Código para atender al cliente. } } }

Page 26: Chat Java con Eclipse

Una vez hecho esto, el servidor simplemente tiene que meterse en un bucle infinito para aceptar conexiones y crear una de estas clases en un hilo aparte cada vez que se conecte un cliente nuevo.

ServidorChat.java

public class ServidorChat{ // Para guardar toda la conversación. private DefaultListModel charla = new DefaultListModel();

public ServidorChat() { // Se crea el socket servidor ServerSocket socketServidor = new ServerSocket(5557);

// Bucle infinito while (true) { // Se espera y acepta un nuevo cliente Socket cliente = socketServidor.accept();

// Se instancia una clase para atender al cliente y se lanza en // un hilo aparte. Runnable nuevoCliente = new HiloDeCliente(charla, cliente); Thread hilo = new Thread(nuevoCliente); hilo.start(); } } }

ALGUNOS DETALLES DEL CÓDIGO DE EJEMPLO EN EL SERVIDOR

He decidido meter toda la charla en un DefaultListModel. Esta es una clase java que no me gusta mucho, pero la uso para no tener que hacerme una y liar más el ejemplo. La

Page 27: Chat Java con Eclipse

clase DefaultListModel implementa un patrón observador. Con esto quiero decir que es posible "suscribirnos" a esa lista, de forma que cuando cualquiera cambie cualquier cosa, podemos enterarnos y actuar en consecuencia.

Cada clase HiloDeCliente recibe este DefaultListModel. Cuando llegue un texto del cliente, lo mete en esta clase, añadiéndolo al final. Como todos los HiloDeCliente que haya en ese momento estarán suscritos a este DefaultListModel, incluido el que lo ha añadido, todos se enterarán del añadido y en consecuencia todos enviarán el nuevo texto a su cliente.

HiloDeCliente.java

// Implementa también ListDataListener para poder suscribirse a cambios// en DefaultListModelpublic class HiloDeCliente implements Runnable, ListDataListener{ public HiloDeCliente(DefaultListModel charla, Socket socket) { ... // Se suscribe a los cambios charla.addListDataListener(this); }

// Trata el cambio de añadido algo al DefaultListModel. public void intervalAdded(ListDataEvent e) { // Obtiene el texto añadido String texto = (String) charla.getElementAt(e.getIndex0()); // y lo envía por el socket. dataOutput.writeUTF(texto); }}

Usar este patrón observador es una forma elegante orientada a objetos de evitar que haya alguien que sepa todos los hilos que hay en marcha y tenga que avisarlos uno a uno cada

Page 28: Chat Java con Eclipse

vez que se añade texto. Nos evita también el tener un array o lista con todos los hilos e ir actualizándolo cada vez que se conecta o desconecta un nuevo hilo.

Vamos ahora con detalles del cliente.