Ejemplos java y C/linux

Google
 

Tutoriales

Enlaces

Licencia

Creative Commons License
Esta obra está bajo una licencia de Creative Commons.
Para reconocer la autoría debes poner el enlace http://www.chuidiang.com

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 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 aparte
public 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.
      }
   }
}

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 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 DefaultListModel

public 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 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.

Estadísticas y comentarios

Numero de visitas desde el 4 Feb 2007: