Chat en Java usando sockets

Veremos como crear un chat en java con Sockets. Nuestra aplicación tendrá dos servicios, que son el Cliente y Servidor.

Tratare de explicar de manera clara para aquellos programadores que apenas empiezan en el mundo de Java, pero en términos generales, hacer un chat con Sockets en Java es bastante sencillo.

cliente servidor sockets en java

El servidor se encargara de levantar el servicio creando un Socket, mientras que el Cliente se conectara a ese Socket mediante un puerto y una dirección Ip.

 

Tabla de contenido
  1. ¿Que es un Socket?
  2. ¿Como funcionan los Sockets?
  3. Como crear un chat con Sockets en Java
  4. Código Java del chat con Sockets
    1. Clase Servidor
    2. Clase Cliente

¿Que es un Socket?

Los sockets son básicamente formas en las que podemos interconectar 2 (o mas) programas mediante el uso de la Internet. En java se utilizan para poder crear conexiones utilizando basicamente una IP/hostname y un puerto para establecer la conexión. Para aprender podemos utilizarla para conectar 2 programas por medio de Internet.

¿Como funcionan los Sockets?

El modelo mas básico de los sockets consta de 2 simples programas, un servidor y un cliente.

Básicamente el programa servidor comienza a “escuchar” en un puerto determinado(nosotros lo especificamos), y posteriormente el programa que la hace de “cliente” debe conocer la ip o nombre de dominio/hostname del servidor y el puerto que esta escuchando, al saber esto simplemente solicita establecer una conexión con el servidor. Es aquí cuando el servidor acepta esa conexión y se puede decir que estos programas están “conectados”, de este modo pueden intercambiar información. En el siguiente video muestro un programa servidor con sockets, explico mas o menos el código, en que consiste y hago una prueba en el cual la conexión es exitosa.

 

Como crear un chat con Sockets en Java

En este vídeo explico como funciona el código en Java para crear un chat simple con Sockets.

Código Java del chat con Sockets

Como lo he mencionado, este proyecto tiene dos clases, Cliente y Servidor.

El siguiente código he procurado que sea limpio y fácil de leer para que cualquier programador pueda entenderlo.

Clase Servidor

A la hora de ejecutar el proyecto, esta clase se debe ejecutar primero, ya que es quien va a escuchar las peticiones.

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;
   
   public Servidor()
   {
      super( "Servidor" );

      Container contenedor = getContentPane();

      campoIntroducir = new JTextField();
      //campoIntroducir.setEditable( false );
      
      ManejaCampo manejador = new ManejaCampo();
      campoIntroducir.addActionListener(manejador);
      contenedor.add( campoIntroducir, BorderLayout.NORTH );
      
      areaPantalla = new JTextArea();
      contenedor.add( new JScrollPane( areaPantalla ), BorderLayout.CENTER );

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

   } 
  
  private class ManejaCampo implements ActionListener
  {
     public void actionPerformed( ActionEvent evento )
     {
       enviarDatos(campoIntroducir.getText());
       campoIntroducir.setText("");
     }
  }  
  
  
   public void ejecutarServidor()
   {    
      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 del bloque try

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

   } // fin del método ejecutarServidor
  
   private void esperarConexion() throws IOException
   {
      mostrarMensaje( "Esperando una conexión\n" );
      conexion = servidor.accept();
      mostrarMensaje( "Conexión " + contador + " recibida de: " +
         conexion.getInetAddress().getHostName() );
   }

   private void obtenerFlujos() throws IOException
   {      
      salida = new ObjectOutputStream( conexion.getOutputStream() );
      salida.flush(); 
      entrada = new ObjectInputStream( conexion.getInputStream() );
      mostrarMensaje( "\nSe establecieron los flujos de E/S\n" );
   }

   private void procesarConexion() throws IOException
   {
      String mensaje = "Conexión exitosa";
      enviarDatos( mensaje );
      //establecerCampoTextoEditable( true );

      do {
         try {
            mensaje = ( String ) entrada.readObject();
            mostrarMensaje( "\n" + mensaje );
         }
         catch ( ClassNotFoundException excepcionClaseNoEncontrada ) {
            mostrarMensaje( "\nSe recibió un tipo de objeto desconocido" );
         }
      } while ( !mensaje.equals( "CLIENTE>>> TERMINAR" ) );
   } 

   private void cerrarConexion() 
   {
      mostrarMensaje( "\nFinalizando la conexión\n" );
 //     establecerCampoTextoEditable( false );

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

   private void enviarDatos( String mensaje )
   {
      try {
         salida.writeObject( "SERVIDOR>>> " + mensaje );
         salida.flush();
         mostrarMensaje( "\nSERVIDOR>>> " + mensaje );
      }
      catch ( IOException excepcionES ) {
         areaPantalla.append( "\nError al escribir objeto" );
      }
   }

   private void mostrarMensaje(String mensajeAMostrar )
   {
      areaPantalla.append( mensajeAMostrar );    
   }
   

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

 

Clase Cliente

Vemos que esta clase en lugar de crear un ServerSocket, crea un Socket normal, al cual le pasaremos por parámetro una dirección ip y un puerto (el puerto no debe estar en uso por ningún otro programa).

 

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 = "";
   private String servidorChat;
   private Socket cliente;
  
   public Cliente(String host)
   {
      super( "Cliente" );

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

      Container contenedor = getContentPane();

      // crear campoIntroducir y registrar componente de escucha
      campoIntroducir = new JTextField();
      ManejaCampoCliente manejador = new ManejaCampoCliente();
      campoIntroducir.addActionListener(manejador);      	 
      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

   private class ManejaCampoCliente implements ActionListener{   
            
      public void actionPerformed( ActionEvent evento )
      {
         enviarDatos(campoIntroducir.getText());
         campoIntroducir.setText( "" );
      }
    }  
    
   
   private void ejecutarCliente() 
   {    
      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 ) {
         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
      }

   }

  
   private void conectarAServidor() throws IOException
   {      
      mostrarMensaje( "Intentando realizar conexión\n" ); 
      cliente = new Socket(InetAddress.getByName( servidorChat ), 12345/*"localhost", 80*/);      
   }

  
   private void obtenerFlujos() throws IOException
   {
      salida = new ObjectOutputStream( cliente.getOutputStream() );      
      salida.flush();       
      entrada = new ObjectInputStream( cliente.getInputStream() );
      mostrarMensaje( "\nSe establecieron los flujos de E/S\n" );
   }
 
   private void procesarConexion() throws IOException
   {
      do { 
         try {
            mensaje = ( String ) entrada.readObject();
            mostrarMensaje( "\n" + mensaje );
         }
         catch ( ClassNotFoundException excepcionClaseNoEncontrada ) {
            mostrarMensaje( "\nSe recibió un objeto de tipo desconocido" );
         }

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

   } 
   
   private void cerrarConexion() 
   {
      mostrarMensaje( "\nCerrando conexión" );   

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

   
   private void enviarDatos( String mensaje )
   {
      try {
         salida.writeObject( "CLIENTE>>> " + mensaje );
         salida.flush();
         mostrarMensaje( "\nCLIENTE>>> " + mensaje );
      }
      catch ( IOException excepcionES ) {
         areaPantalla.append( "\nError al escribir el objeto" );
      }
   }

   private void mostrarMensaje( final String mensajeAMostrar )
   {
      areaPantalla.append( mensajeAMostrar );
   }

   public static void main( String args[] )
   {
      Cliente aplicacion;

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

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

} 

Espero que te haya gustado y te haya sido de ayuda para tu proyecto. Si quieres aprender más sobre Java, visita nuestra sección de tutoriales para Java.

Recomendado:   CONSTANTES EN JAVA (final static)
Subir