Vous êtes sur la page 1sur 12

Mg.

Freddy Toribio Huayta Meza

Como Hacer un Chat con Sockets en Java en Netbeans

En este nuevo post mostraremos como hacer un chat mediante el uso de Sockets en Java en el ambiente de programación
Netbeans. Los Sockets sirven para comunicar procesos de diferentes máquinas de una red.

Haremos un servidor y un cliente utilizando Sockets.

Del lado del Servidor se tiene un bucle infinito que espera conexiones de clientes. Cuando un cliente se conecta el servidor
acepta la conexión y genera dos threads: uno para enviar datos y el otro para recibirlos.

Del lado del Cliente se tiene que esperar un Servidor para poder conectarse, cuando se conecta al servidor se generan
dos threads, al igual que en el Servidor uno para enviar y otro para recibir los datos.

Los threads que se generan del lado del servidor y del cliente son los mismos.
La clase principal del Servidor es idéntica a la clase principal del cliente; la única diferencia está en el main, el servidor
espera conexiones del cliente y el cliente busca servidor para conectarse.

Para nuestro ejemplo utilizaremos localhost para poder correr el programa en nuestra propia máquina.

Es importante tener en cuenta que puerto se va a utilizar para poder abrirlo con anterioridad, en nuestro caso abriremos
el puerto 11111.

Se debe conocer que las asignaciones a los puertos comprendidos entre los valores (0 - 1023) están determinados por
la IANA (Internet Assigned Numbers Authority). y no se los puede utilizar de otra manera.

Se puede utilizar los puertos comprendidos entre los valores (1024 - 65535).

Nuestro programa cuenta con dos paquetes, uno para el servidor y otro para el cliente; los mismo que contiene threads
idénticos para envío y recepción de datos.

Empezaremos describiendo las clases del lado del servidor:

Clase PrincipalChat:
Esta clase implementa la interfaz gráfica para poder mostrar los mensajes entrantes y un JTextField para poder enviarlos.
La interfaz contiene un menú para poder salir del programa.

En el main se puede ver que se espera conexiones de clientes.


1. package servidor;
2. import java.awt.BorderLayout;
3. import java.awt.Color;
4. import java.awt.event.ActionEvent;
5. import java.awt.event.ActionListener;
6. import java.io.IOException;
7. import java.net.InetAddress;
8. import java.net.ServerSocket;
9. import java.net.Socket;
10. import java.util.concurrent.ExecutorService;
11. import java.util.concurrent.Executors;
12. import java.util.logging.Level;
13. import java.util.logging.Logger;
14. import javax.swing.*;
15.
16. /**Clase que se encarga de correr los threads de enviar y recibir texto

1
Mg. Freddy Toribio Huayta Meza

17. * y de crear la interfaz grafica.


18. *
19. */
20. public class PrincipalChat extends JFrame{
21. public JTextField campoTexto; //Para mostrar mensajes de los usuarios
22. public JTextArea areaTexto; //Para ingresar mensaje a enviar
23. private static ServerSocket servidor; //
24. private static Socket conexion; //Socket para conectarse con el cliente
25. private static String ip = "127.0.0.1"; //ip a la cual se conecta
26.
27. public static PrincipalChat main;
28.
29. public PrincipalChat(){
30. super("Servidor"); //Establece titulo al Frame
31.
32. campoTexto = new JTextField(); //crea el campo para texto
33. campoTexto.setEditable(false); //No permite que sea editable el campo de texto
34. add(campoTexto, BorderLayout.NORTH); //Coloca el campo de texto en la parte superior
35.
36. areaTexto = new JTextArea(); //Crear displayArea
37. areaTexto.setEditable(false);
38. add(new JScrollPane(areaTexto), BorderLayout.CENTER);
39. areaTexto.setBackground(Color.orange); //Pone de color cyan al areaTexto
40. areaTexto.setForeground(Color.BLACK); //pinta azul la letra en el areaTexto
41. campoTexto.setForeground(Color.BLACK); //pinta toja la letra del mensaje a enviar
42.
43.
44. //Crea menu Archivo y submenu Salir, ademas agrega el submenu al menu
45. JMenu menuArchivo = new JMenu("Archivo");
46. JMenuItem salir = new JMenuItem("Salir");
47. menuArchivo.add(salir); //Agrega el submenu Salir al menu menuArchivo
48.
49. JMenuBar barra = new JMenuBar(); //Crea la barra de menus
50. setJMenuBar(barra); //Agrega barra de menus a la aplicacion
51. barra.add(menuArchivo); //agrega menuArchivo a la barra de menus
52.
53. //Accion que se realiza cuando se presiona el submenu Salir
54. salir.addActionListener(new ActionListener() { //clase interna anonima
55. public void actionPerformed(ActionEvent e) {
56. System.exit(0); //Sale de la aplicacion
57. }
58. });
59.
60. setSize(300, 320); //Establecer tamano a ventana
61. setVisible(true); //Pone visible la ventana
62. }

2
Mg. Freddy Toribio Huayta Meza

63. //Para mostrar texto en displayArea


64. public void mostrarMensaje(String mensaje) {
65. areaTexto.append(mensaje + "\n");
66. }
67. public void habilitarTexto(boolean editable) {
68. campoTexto.setEditable(editable);
69. }
70.
71. /**
72. * @param args the command line arguments
73. */
74. public static void main(String[] args) {
75. PrincipalChat main = new PrincipalChat(); //Instanciacion de la clase Principalchat
76. main.setLocationRelativeTo(null); //Centrar el JFrame
77. main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //habilita cerrar la ventana
78. ExecutorService executor = Executors.newCachedThreadPool(); //Para correr los threads
79.
80. try {
81. //main.mostrarMensaje("No se encuentra Servidor");
82. servidor = new ServerSocket(11111, 100);
83. main.mostrarMensaje("Esperando Cliente ...");
84.
85. //Bucle infinito para esperar conexiones de los clientes
86. while (true){
87. try {
88. conexion = servidor.accept(); //Permite al servidor aceptar
conexiones
89.
90. //main.mostrarMensaje("Conexion Establecida");
91. main.mostrarMensaje("Conectado a :
" +conexion.getInetAddress().getHostName());
92.
93. main.habilitarTexto(true); //permite escribir texto para enviar
94.
95. //Ejecucion de los threads
96. executor.execute(new Recibe(conexion, main)); //client
97. executor.execute(new Envia(conexion, main));
98. } catch (IOException ex) {
99. Logger.getLogger(PrincipalChat.class.getName()).log(Level.SEVERE,null,
ex);
100. }
101. }
102. } catch (IOException ex) {
103. Logger.getLogger(PrincipalChat.class.getName()).log(Level.SEVERE, null, ex);
104. } //Fin del catch
105. finally {

3
Mg. Freddy Toribio Huayta Meza

106. }
107. executor.shutdown();
108. }
109. }

Clase ThreadEnvia:
En esta clase establecemos nuestro canal de salida tipo ObjectOutputStream, el cual nos sirve para escribir el
mensaje, enviarlo y mostrarlo en pantalla mediante el método enviarDatos().
Además, declaramos la variable conexión tipo Socket, la cual se encarga de establecer el flujo de datos entre
cliente y servidor.
1. package servidor;
2. import java.io.IOException;
3. import java.io.ObjectOutputStream;
4. import java.net.Socket;
5. import java.awt.event.ActionEvent;
6. import java.awt.event.ActionListener;
7. import java.net.SocketException;
8.
9. public class ThreadEnvia implements Runnable {
10. private final PrincipalChat main;
11. private ObjectOutputStream salida;
12. private String mensaje;
13. private Socket conexion;
14.
15. public ThreadEnvia(Socket conexion, final PrincipalChat main){
16. this.conexion = conexion;
17. this.main = main;
18.
19. //Evento que ocurre al escribir en el areaTexto
20. main.campoTexto.addActionListener(new ActionListener() {
21. public void actionPerformed(ActionEvent event) {
22. mensaje = event.getActionCommand();
23. enviarDatos(mensaje); //se envia el mensaje
24. main.campoTexto.setText(""); //borra el texto del enterfield
25. } //Fin metodo actionPerformed
26. }
27. );//Fin llamada a addActionListener
28. }
29.
30. //enviar objeto a cliente
31. private void enviarDatos(String mensaje){
32. try {
33. salida.writeObject("Servidor>>> " + mensaje);
34. salida.flush(); //flush salida a cliente
35. main.mostrarMensaje("Servidor>>> " + mensaje);
36. } //Fin try

4
Mg. Freddy Toribio Huayta Meza

37. catch (IOException ioException){


38. main.mostrarMensaje("Error escribiendo Mensaje");
39. } //Fin catch
40.
41. } //Fin methodo enviarDatos
42.
43. //manipula areaPantalla en el hilo despachador de eventos
44. public void mostrarMensaje(String mensaje) {
45. main.areaTexto.append(mensaje);
46. }
47.
48. public void run() {
49. try {
50. salida = new ObjectOutputStream(conexion.getOutputStream());
51. salida.flush();
52. } catch (SocketException ex) {
53. } catch (IOException ioException) {
54. ioException.printStackTrace();
55. } catch (NullPointerException ex) {
56. }
57. }
58.
59. }

Clase ThreadRecibe:
En esta clase establecemos nuestro canal de entrada tipo ObjectInputStream, el cual se encarga de recibir los mensajes
enviados por el cliente o servidor.
Aquí se procesa los mensajes recibidos y luego son mostrados en pantalla.
Es importante aclarar que se debe cerrar el canal de entrada de datos y el Socket de conexión una vez finalizado el flujo
de datos.

1. package servidor;
2. import java.io.EOFException;
3. import java.io.IOException;
4. import java.io.ObjectInputStream;
5. import java.net.Socket;
6. import java.net.SocketException;
7. import java.util.logging.Level;
8. import java.util.logging.Logger;
9.
10. public class ThreadRecibe implements Runnable {
11. private final PrincipalChat main;
12. private String mensaje;
13. private ObjectInputStream entrada;
14. private Socket cliente;
15.

5
Mg. Freddy Toribio Huayta Meza

16.
17. //Inicializar chatServer y configurar GUI
18. public ThreadRecibe(Socket cliente, PrincipalChat main){
19. this.cliente = cliente;
20. this.main = main;
21. }
22.
23. public void mostrarMensaje(String mensaje) {
24. main.areaTexto.append(mensaje);
25. }
26.
27. public void run() {
28. try {
29. entrada = new ObjectInputStream(cliente.getInputStream());
30. } catch (IOException ex) {
31. Logger.getLogger(ThreadRecibe.class.getName()).log(Level.SEVERE, null, ex);
32. }
33. do { //procesa los mensajes enviados dsd el servidor
34. try {//leer el mensaje y mostrarlo
35. mensaje = (String) entrada.readObject(); //leer nuevo mensaje
36. main.mostrarMensaje(mensaje);
37. } //fin try
38. catch (SocketException ex) {
39. }
40. catch (EOFException eofException) {
41. main.mostrarMensaje("Fin de la conexion");
42. break;
43. } //fin catch
44. catch (IOException ex) {
45. Logger.getLogger(ThreadRecibe.class.getName()).log(Level.SEVERE, null, ex);
46. } catch (ClassNotFoundException classNotFoundException) {
47. main.mostrarMensaje("Objeto desconocido");
48. } //fin catch
49.
50. } while (!mensaje.equals("Servidor>>> TERMINATE")); //Ejecuta hasta que el server
escriba TERMINATE
51.
52. try {
53. entrada.close(); //cierra input Stream
54. cliente.close(); //cieraa Socket
55. } //Fin try
56. catch (IOException ioException) {
57. ioException.printStackTrace();
58. } //fin catch
59.
60. main.mostrarMensaje("Fin de la conexion");

6
Mg. Freddy Toribio Huayta Meza

61. System.exit(0);
62. }
63. }

En el paquete Cliente encontramos:


Clase PrincipalChat:
Esta clase implementa la interfaz gráfica para poder mostrar los mensajes entrantes y un JTextField para poder enviarlos.
La interfaz contiene un menú para poder salir del programa.
Esta clase busca servidores para poder conectarse.

1. package cliente;
2. import java.awt.BorderLayout;
3. import java.awt.Color;
4. import java.awt.event.ActionEvent;
5. import java.awt.event.ActionListener;
6. import java.io.EOFException;
7. import java.io.IOException;
8. import java.net.InetAddress;
9. import java.net.ServerSocket;
10. import java.net.Socket;
11. import java.util.concurrent.ExecutorService;
12. import java.util.concurrent.Executors;
13. import java.util.logging.Level;
14. import java.util.logging.Logger;
15. import javax.swing.*;
16.
17. /**Clase que se encarga de correr los threads de enviar y recibir texto
18. * y de crear la interfaz grafica.
19. */
20. public class PrincipalChat extends JFrame{
21. public JTextField campoTexto; //Para mostrar mensajes de los usuarios
22. public JTextArea areaTexto; //Para ingresar mensaje a enviar
23. private static ServerSocket servidor; //
24. private static Socket cliente; //Socket para conectarse con el cliente
25. private static String ip = "127.0.0.1"; //ip a la cual se conecta
26.
27. public static PrincipalChat main;
28.
29. public PrincipalChat(){
30. super("Cliente"); //Establece titulo al Frame
31.
32. campoTexto = new JTextField(); //crea el campo para texto
33. campoTexto.setEditable(false); //No permite que sea editable el campo de texto
34. add(campoTexto, BorderLayout.NORTH); //Coloca el campo de texto en la parte superior
35.
36.

7
Mg. Freddy Toribio Huayta Meza

37. areaTexto = new JTextArea(); //Crear displayArea


38. areaTexto.setEditable(false);
39. add(new JScrollPane(areaTexto), BorderLayout.CENTER);
40. areaTexto.setBackground(Color.orange); //Pone de color cyan al displayArea
41. areaTexto.setForeground(Color.BLACK); //pinta azul la letra en el displayArea
42. campoTexto.setForeground(Color.BLACK); //pinta toja la letra del mensaje a enviar
43.
44.
45. //Crea menu Archivo y submenu Salir, ademas agrega el submenu al menu
46. JMenu menuArchivo = new JMenu("Archivo");
47. JMenuItem salir = new JMenuItem("Salir");
48. menuArchivo.add(salir); //Agrega el submenu Salir al menu menuArchivo
49.
50. JMenuBar barra = new JMenuBar(); //Crea la barra de menus
51. setJMenuBar(barra); //Agrega barra de menus a la aplicacion
52. barra.add(menuArchivo); //agrega menuArchivo a la barra de menus
53.
54. //Accion que se realiza cuando se presiona el submenu Salir
55. salir.addActionListener(new ActionListener() { //clase interna anonima
56. public void actionPerformed(ActionEvent e) {
57. System.exit(0); //Sale de la aplicacion
58. }
59. });
60.
61. setSize(300, 320); //Establecer tamano a ventana
62. setVisible(true); //Pone visible la ventana
63. }
64.
65. //Para mostrar texto en displayArea
66. public void mostrarMensaje(String mensaje) {
67. areaTexto.append(mensaje + "\n");
68. }
69. public void habilitarTexto(boolean editable) {
70. campoTexto.setEditable(editable);
71. }
72.
73. /**
74. * @param args the command line arguments
75. */
76. public static void main(String[] args) {
77. PrincipalChat main = new PrincipalChat(); //Instanciacion de la clase Principalchat
78. main.setLocationRelativeTo(null); //Centrar el JFrame
79. main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //habilita cerrar la ventana
80. ExecutorService executor = Executors.newCachedThreadPool(); //Para correr los threads
81.
82. try {

8
Mg. Freddy Toribio Huayta Meza

83. main.mostrarMensaje("Buscando Servidor ...");


84. cliente = new Socket(InetAddress.getByName(ip), 11111); //comunicarme con el
servidor
85. main.mostrarMensaje("Conectado a :" +cliente.getInetAddress().getHostName());
86.
87. main.habilitarTexto(true); //habilita el texto
88.
89. //Ejecucion de los Threads
90. executor.execute(new ThreadRecibe(cliente, main));
91. executor.execute(new ThreadEnvia(cliente, main));
92.
93. } catch (IOException ex) {
94. Logger.getLogger(PrincipalChat.class.getName()).log(Level.SEVERE, null, ex);
95. } //Fin del catch
96. finally {
97. }
98. executor.shutdown();
99. }
100. }

Las clases descritas en el paquete Cliente: ThreadRecibe y ThreadEnvia son exactamente las mismas que
se describieron en el paquete Servidor.

Nuestro proyecto se vera asi:

El resultado final se mostrará de la siguiente manera:

9
Mg. Freddy Toribio Huayta Meza

Sockets en Java (cliente y servidor)

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 conenctar 2 programas por medio de Internet.

¿Como funciona?

El modelo más básico de los sockets consta de 2 simples programas, un servidor y un cliente. Basicamente 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 aqui cuando el servidor acepta esa conexión
y se puede decir que estos programas estan “conectados”, de este modo pueden intercambiar información. En el siguiente
video muestro un programa servidor con sockets, explico mas o menos el codigo, en que consiste y hago una prueba en
el cual la conexión es exitosa.

Notas:

* Ambos programas (servidor y cliente) no necesitan estar programados en Java, es posible programarlos en lenguajes
de programación diferentes, o inclusive programar un servidor en java y utilizar un cliente ya existente que pueda
conectarse a un puerto especificado.

* El cliente debe de conocer tanto el puerto a utilizar como la IP o dominio del servidor, mientras el servidor solo debe
conocer el puerto de conexión

A continuación, se presenta el código en java de un servidor muy simple, lo que hace es escuchar el puerto 5000, cuando
un cliente se conecta este envía un mensaje de confirmación al cliente, luego el cliente al enviar su primer mensaje, el
servidor envía un segundo mensaje y se cierra la conexión. También el de un cliente muy simple solo para que se vea la
diferencia, de como se pide la conexión al servidor, el cliente únicamente envía un mensaje de texto, pero no recibe
información.

Codigo fuente del servidor

import java.net.*;

import java.io.*;

public class Conex {

final int PUERTO=5000;

ServerSocket sc;

Socket so;

DataOutputStream salida;

String mensajeRecibido;

//SERVIDOR

public void initServer()

BufferedReader entrada;
10
Mg. Freddy Toribio Huayta Meza

try

sc = new ServerSocket(PUERTO );/* crea socket servidor que escuchara en puerto 5000*/

so=new Socket();

System.out.println("Esperando una conexión:");

so = sc.accept();

//Inicia el socket, ahora esta esperando una conexión por parte del cliente

System.out.println("Un cliente se ha conectado.");

//Canales de entrada y salida de datos

entrada = new BufferedReader(new InputStreamReader(so.getInputStream()));

salida = new DataOutputStream(so.getOutputStream());

System.out.println("Confirmando conexion al cliente....");

salida.writeUTF("Conexión exitosa...n envia un mensaje :D");

//Recepcion de mensaje

mensajeRecibido = entrada.readLine();

System.out.println(mensajeRecibido);

salida.writeUTF("Se recibio tu mensaje.n Terminando conexion...");

salida.writeUTF("Gracias por conectarte, adios!");

System.out.println("Cerrando conexión...");

sc.close();//Aqui se cierra la conexión con el cliente

} catch(Exception e )

System.out.println("Error: "+e.getMessage());

Código fuente cliente simple

view source
11
Mg. Freddy Toribio Huayta Meza

import java.net.*;

import java.io.*;

public class Conex {

final String HOST = "localhost";

final int PUERTO=5000;

Socket sc;

DataOutputStream mensaje;

DataInputStream entrada;

//Cliente

public void initClient() /*ejecuta este metodo para correr el cliente */

try

sc = new Socket( HOST , PUERTO ); /*conectar a un servidor en localhost con puerto 5000*/

//creamos el flujo de datos por el que se enviara un mensaje

mensaje = new DataOutputStream(sc.getOutputStream());

//enviamos el mensaje

mensaje.writeUTF("hola que tal!!");

//cerramos la conexión

sc.close();

} catch(Exception e )

System.out.println("Error: "+e.getMessage());

12

Vous aimerez peut-être aussi