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.
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.
¿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.
https://www.youtube.com/watch?v=e1iDtNmSS3s
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.
Si quieres conocer otros artículos parecidos a Chat en Java usando sockets puedes visitar la categoría Java.
Entradas relacionadas