Foros del Web » Programación para mayores de 30 ;) » Java »

Chat en java

Estas en el tema de Chat en java en el foro de Java en Foros del Web. Buenas, estoy intentando implementar un servidor de un chat Necesito llevar una lista de los conectados: he pensado en la clase DefaultListModel, pero no entiendo ...
  #1 (permalink)  
Antiguo 02/05/2011, 09:06
 
Fecha de Ingreso: mayo-2011
Mensajes: 11
Antigüedad: 13 años
Puntos: 0
Chat en java

Buenas, estoy intentando implementar un servidor de un chat
Necesito llevar una lista de los conectados: he pensado en la clase DefaultListModel, pero no entiendo muy bien como esta clase mantiene informados al resto de los conectados mediando los metodos de fire..
Tambien necesito conocer los flujos necesarios, y habia pensado en la clase SocketChannel, pero tampoco acabo de entender como funciona..

Pueden aconsejarme, darme idea u orientarme?
Muchas gracias!!
  #2 (permalink)  
Antiguo 07/05/2011, 21:54
 
Fecha de Ingreso: diciembre-2010
Mensajes: 26
Antigüedad: 13 años, 4 meses
Puntos: 2
Respuesta: Chat en java

aca esta un ejemplo para que te guies, este es un chat entre 2 pc via lan, configuras las ip de cada una entre cliente y servidor y listo ... quizas te ayude en algo.. saludos


Código Javascript:
Ver original
  1. // Cliente que lee y muestra la informaci�n que le env�a un Servidor.
  2. import java.io.*;
  3. import java.net.*;
  4. import java.awt.*;
  5. import java.awt.event.*;
  6. import javax.swing.*;
  7.  
  8. public class Cliente extends JFrame {
  9.    private JTextField campoIntroducir;
  10.    private JTextArea areaPantalla;
  11.    private ObjectOutputStream salida;
  12.    private ObjectInputStream entrada;
  13.    private String mensaje = "";
  14.    private String servidorChat;
  15.    private Socket cliente;
  16.  
  17.    // inicializar servidorChat y configurar GUI
  18.    public Cliente( String host )
  19.    {
  20.       super( "Cliente" );
  21.  
  22.       servidorChat = host; // establecer el servidor al que se va a conectar este cliente
  23.  
  24.       Container contenedor = getContentPane();
  25.  
  26.       // crear campoIntroducir y registrar componente de escucha
  27.       campoIntroducir = new JTextField();
  28.       campoIntroducir.setEditable( false );
  29.       campoIntroducir.addActionListener(
  30.          new ActionListener() {
  31.  
  32.             // enviar mensaje al servidor
  33.             public void actionPerformed( ActionEvent evento )
  34.             {
  35.                enviarDatos( evento.getActionCommand() );
  36.                campoIntroducir.setText( "" );
  37.             }
  38.          }  
  39.       );
  40.  
  41.       contenedor.add( campoIntroducir, BorderLayout.NORTH );
  42.  
  43.       // crear areaPantalla
  44.       areaPantalla = new JTextArea();
  45.       contenedor.add( new JScrollPane( areaPantalla ),
  46.          BorderLayout.CENTER );
  47.  
  48.       setSize( 300, 150 );
  49.       setVisible( true );
  50.  
  51.    } // fin del constructor de Cliente
  52.  
  53.    // conectarse al servidor y procesar mensajes del servidor
  54.    private void ejecutarCliente()
  55.    {
  56.       // conectarse al servidor, obtener flujos, procesar la conexi�n
  57.       try {
  58.          conectarAServidor(); // Paso 1: crear un socket para realizar la conexi�n
  59.          obtenerFlujos();      // Paso 2: obtener los flujos de entrada y salida
  60.          procesarConexion(); // Paso 3: procesar la conexi�n
  61.       }
  62.  
  63.       // el servidor cerr� la conexi�n
  64.       catch ( EOFException excepcionEOF ) {
  65.          System.err.println( "El cliente termino la conexi�n" );
  66.       }
  67.  
  68.       // procesar los problemas que pueden ocurrir al comunicarse con el servidor
  69.       catch ( IOException excepcionES ) {
  70.          excepcionES.printStackTrace();
  71.       }
  72.  
  73.       finally {
  74.          cerrarConexion(); // Paso 4: cerrar la conexi�n
  75.       }
  76.  
  77.    } // fin del m�todo ejecutarCliente
  78.  
  79.    // conectarse al servidor
  80.    private void conectarAServidor() throws IOException
  81.    {      
  82.       mostrarMensaje( "Intentando realizar conexi�n\n" );
  83.  
  84.       // crear Socket para realizar la conexi�n con el servidor
  85.       cliente = new Socket( InetAddress.getByName( servidorChat ), 12345 );
  86.  
  87.       // mostrar la informaci�n de la conexi�n
  88.       mostrarMensaje( "Conectado a: " +
  89.          cliente.getInetAddress().getHostName() );
  90.    }
  91.  
  92.    // obtener flujos para enviar y recibir datos
  93.    private void obtenerFlujos() throws IOException
  94.    {
  95.       // establecer flujo de salida para los objetos
  96.       salida = new ObjectOutputStream( cliente.getOutputStream() );      
  97.       salida.flush(); // vac�ar b�fer de salida para enviar informaci�n de encabezado
  98.  
  99.       // establecer flujo de entrada para los objetos
  100.       entrada = new ObjectInputStream( cliente.getInputStream() );
  101.  
  102.       mostrarMensaje( "\nSe recibieron los flujos de E/S\n" );
  103.    }
  104.  
  105.    // procesar la conexi�n con el servidor
  106.    private void procesarConexion() throws IOException
  107.    {
  108.       // habilitar campoIntroducir para que el usuario del cliente pueda enviar mensajes
  109.       establecerCampoTextoEditable( true );
  110.  
  111.       do { // procesar mensajes enviados del servidor
  112.  
  113.          // leer mensaje y mostrarlo en pantalla
  114.          try {
  115.             mensaje = ( String ) entrada.readObject();
  116.             mostrarMensaje( "\n" + mensaje );
  117.          }
  118.  
  119.          // atrapar los problemas que pueden ocurrir al leer del servidor
  120.          catch ( ClassNotFoundException excepcionClaseNoEncontrada ) {
  121.             mostrarMensaje( "\nSe recibi� un objeto de tipo desconocido" );
  122.          }
  123.  
  124.       } while ( !mensaje.equals( "SERVIDOR>>> TERMINAR" ) );
  125.  
  126.    } // fin del m�todo procesarConexion
  127.  
  128.    // cerrar flujos y socket
  129.    private void cerrarConexion()
  130.    {
  131.       mostrarMensaje( "\nCerrando conexi�n" );
  132.       establecerCampoTextoEditable( false ); // deshabilitar campoIntroducir
  133.  
  134.       try {
  135.          salida.close();
  136.          entrada.close();
  137.          cliente.close();
  138.       }
  139.       catch( IOException excepcionES ) {
  140.          excepcionES.printStackTrace();
  141.       }
  142.    }
  143.  
  144.    // enviar mensaje al servidor
  145.    private void enviarDatos( String mensaje )
  146.    {
  147.       // enviar objeto al servidor
  148.       try {
  149.          salida.writeObject( "CLIENTE>>> " + mensaje );
  150.          salida.flush();
  151.          mostrarMensaje( "\nCLIENTE>>> " + mensaje );
  152.       }
  153.  
  154.       // procesar los problemas que pueden ocurrir al enviar el objeto
  155.       catch ( IOException excepcionES ) {
  156.          areaPantalla.append( "\nError al escribir el objeto" );
  157.       }
  158.    }
  159.  
  160.    // m�todo utilitario que es llamado desde otros subprocesos para manipular a
  161.    // areaPantalla en el subproceso despachador de eventos
  162.    private void mostrarMensaje( final String mensajeAMostrar )
  163.    {
  164.       // mostrar mensaje del subproceso de ejecuci�n de la GUI
  165.       SwingUtilities.invokeLater(
  166.          new Runnable() {  // clase interna para asegurar que la GUI se actualice apropiadamente
  167.  
  168.             public void run() // actualiza areaPantalla
  169.             {
  170.                areaPantalla.append( mensajeAMostrar );
  171.                areaPantalla.setCaretPosition(
  172.                   areaPantalla.getText().length() );
  173.             }
  174.  
  175.          }  // fin de la clase interna
  176.  
  177.       ); // fin de la llamada a SwingUtilities.invokeLater
  178.    }
  179.  
  180.    // m�todo utilitario que es llamado desde otros subprocesos para manipular a
  181.    // campoIntroducir en el subproceso despachador de eventos
  182.    private void establecerCampoTextoEditable( final boolean editable )
  183.    {
  184.       // mostrar mensaje del subproceso de ejecuci�n de la GUI
  185.       SwingUtilities.invokeLater(
  186.          new Runnable() {  // clase interna para asegurar que la GUI se actualice apropiadamente
  187.  
  188.             public void run()  // establece la capacidad de modificar campoIntroducir
  189.             {
  190.                campoIntroducir.setEditable( editable );
  191.             }
  192.  
  193.          }  // fin de la clase interna
  194.  
  195.       ); // fin de la llamada a SwingUtilities.invokeLater
  196.    }
  197.  
  198.    public static void main( String args[] )
  199.    {
  200.       Cliente aplicacion;
  201.  
  202.       if ( args.length == 0 )
  203.          aplicacion = new Cliente( "192.200.101.131" );
  204.       else
  205.          aplicacion = new Cliente( args[ 0 ] );
  206.  
  207.       aplicacion.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
  208.       aplicacion.ejecutarCliente();
  209.    }
  210.  
  211. } // fin de la clase Cliente
  #3 (permalink)  
Antiguo 07/05/2011, 21:54
 
Fecha de Ingreso: diciembre-2010
Mensajes: 26
Antigüedad: 13 años, 4 meses
Puntos: 2
Respuesta: Chat en java

Código Javascript:
Ver original
  1. package chat;
  2.  
  3. // Configurar un servidor que reciba una conexión de un cliente, envíe
  4. // una cadena al cliente y cierre la conexión.
  5. import java.io.*;
  6. import java.net.*;
  7. import java.awt.*;
  8. import java.awt.event.*;
  9. import javax.swing.*;
  10.  
  11. public class Servidor extends JFrame {
  12.    private JTextField campoIntroducir;
  13.    private JTextArea areaPantalla;
  14.    private ObjectOutputStream salida;
  15.    private ObjectInputStream entrada;
  16.    private ServerSocket servidor;
  17.    private Socket conexion;
  18.    private int contador = 1;
  19.  
  20.    // configurar GUI
  21.    public Servidor()
  22.    {
  23.       super( "Servidor" );
  24.  
  25.       Container contenedor = getContentPane();
  26.  
  27.       // crear campoIntroducir y registrar componente de escucha
  28.       campoIntroducir = new JTextField();
  29.       campoIntroducir.setEditable( false );
  30.       campoIntroducir.addActionListener(
  31.          new ActionListener() {
  32.  
  33.             // enviar mensaje al cliente
  34.             public void actionPerformed( ActionEvent evento )
  35.             {
  36.                enviarDatos( evento.getActionCommand() );
  37.                campoIntroducir.setText( "" );
  38.             }
  39.          }  
  40.       );
  41.  
  42.       contenedor.add( campoIntroducir, BorderLayout.NORTH );
  43.  
  44.       // crear areaPantalla
  45.       areaPantalla = new JTextArea();
  46.       contenedor.add( new JScrollPane( areaPantalla ),
  47.          BorderLayout.CENTER );
  48.  
  49.       setSize( 300, 150 );
  50.       setVisible( true );
  51.  
  52.    } // fin del constructor de Servidor
  53.  
  54.    // configurar y ejecutar el servidor
  55.    public void ejecutarServidor()
  56.    {
  57.       // configurar servidor para que reciba conexiones; procesar las conexiones
  58.       try {
  59.  
  60.          // Paso 1: crear un objeto ServerSocket.
  61.          servidor = new ServerSocket( 12345, 100 );
  62.  
  63.          while ( true ) {
  64.  
  65.             try {
  66.                esperarConexion(); // Paso 2: esperar una conexión.
  67.                obtenerFlujos();        // Paso 3: obtener flujos de entrada y salida.
  68.                procesarConexion(); // Paso 4: procesar la conexión.
  69.             }
  70.  
  71.             // procesar excepción EOFException cuando el cliente cierre la conexión
  72.             catch ( EOFException excepcionEOF ) {
  73.                System.err.println( "El servidor terminó la conexión" );
  74.             }
  75.  
  76.             finally {
  77.                cerrarConexion();   // Paso 5: cerrar la conexión.
  78.                ++contador;
  79.             }
  80.  
  81.          } // fin de instrucción while
  82.  
  83.       } // fin del bloque try
  84.  
  85.       // procesar problemas con E/S
  86.       catch ( IOException excepcionES ) {
  87.          excepcionES.printStackTrace();
  88.       }
  89.  
  90.    } // fin del método ejecutarServidor
  91.  
  92.    // esperar que la conexión llegue, después mostrar información de la conexión
  93.    private void esperarConexion() throws IOException
  94.    {
  95.       mostrarMensaje( "Esperando una conexión\n" );
  96.       conexion = servidor.accept(); // permitir al servidor aceptar la conexión            
  97.       mostrarMensaje( "Conexión " + contador + " recibida de: " +
  98.          conexion.getInetAddress().getHostName() );
  99.    }
  100.  
  101.    // obtener flujos para enviar y recibir datos
  102.    private void obtenerFlujos() throws IOException
  103.    {
  104.       // establecer flujo de salida para los objetos
  105.       salida = new ObjectOutputStream( conexion.getOutputStream() );
  106.       salida.flush(); // vaciar búfer de salida para enviar información de encabezado
  107.  
  108.       // establecer flujo de entrada para los objetos
  109.       entrada = new ObjectInputStream( conexion.getInputStream() );
  110.  
  111.       mostrarMensaje( "\nSe recibieron los flujos de E/S\n" );
  112.    }
  113.  
  114.    // procesar la conexión con el cliente
  115.    private void procesarConexion() throws IOException
  116.    {
  117.       // enviar mensaje de conexión exitosa al cliente
  118.       String mensaje = "Conexión exitosa";
  119.       enviarDatos( mensaje );
  120.  
  121.       // habilitar campoIntroducir para que el usuario del servidor pueda enviar mensajes
  122.       establecerCampoTextoEditable( true );
  123.  
  124.       do { // procesar los mensajes enviados por el cliente
  125.  
  126.          // leer el mensaje y mostrarlo en pantalla
  127.          try {
  128.             mensaje = ( String ) entrada.readObject();
  129.             mostrarMensaje( "\n" + mensaje );
  130.          }
  131.  
  132.          // atrapar problemas que pueden ocurrir al tratar de leer del cliente
  133.          catch ( ClassNotFoundException excepcionClaseNoEncontrada ) {
  134.             mostrarMensaje( "\nSe recibió un tipo de objeto desconocido" );
  135.          }
  136.  
  137.       } while ( !mensaje.equals( "CLIENTE>>> TERMINAR" ) );
  138.  
  139.    } // fin del método procesarConexion
  140.  
  141.    // cerrar flujos y socket
  142.    private void cerrarConexion()
  143.    {
  144.       mostrarMensaje( "\nFinalizando la conexión\n" );
  145.       establecerCampoTextoEditable( false ); // deshabilitar campoIntroducir
  146.  
  147.       try {
  148.          salida.close();
  149.          entrada.close();
  150.          conexion.close();
  151.       }
  152.       catch( IOException excepcionES ) {
  153.          excepcionES.printStackTrace();
  154.       }
  155.    }
  156.  
  157.    // enviar mensaje al cliente
  158.    private void enviarDatos( String mensaje )
  159.    {
  160.       // enviar objeto al cliente
  161.       try {
  162.          salida.writeObject( "SERVIDOR>>> " + mensaje );
  163.          salida.flush();
  164.          mostrarMensaje( "\nSERVIDOR>>> " + mensaje );
  165.       }
  166.  
  167.       // procesar problemas que pueden ocurrir al enviar el objeto
  168.       catch ( IOException excepcionES ) {
  169.          areaPantalla.append( "\nError al escribir objeto" );
  170.       }
  171.    }
  172.  
  173.    // método utilitario que es llamado desde otros subprocesos para manipular a
  174.    // areaPantalla en el subproceso despachador de eventos
  175.    private void mostrarMensaje( final String mensajeAMostrar )
  176.    {
  177.       // mostrar mensaje del subproceso de ejecución despachador de eventos
  178.       SwingUtilities.invokeLater(
  179.          new Runnable() {  // clase interna para asegurar que la GUI se actualice apropiadamente
  180.  
  181.             public void run() // actualiza areaPantalla
  182.             {
  183.                areaPantalla.append( mensajeAMostrar );
  184.                areaPantalla.setCaretPosition(
  185.                   areaPantalla.getText().length() );
  186.             }
  187.  
  188.          }  // fin de la clase interna
  189.  
  190.       ); // fin de la llamada a SwingUtilities.invokeLater
  191.    }
  192.  
  193.    // método utilitario que es llamado desde otros subprocesos para manipular a
  194.    // campoIntroducir en el subproceso despachador de eventos
  195.    private void establecerCampoTextoEditable( final boolean editable )
  196.    {
  197.       // mostrar mensaje del subproceso de ejecución despachador de eventos
  198.       SwingUtilities.invokeLater(
  199.          new Runnable() {  // clase interna para asegurar que la GUI se actualice apropiadamente
  200.  
  201.             public void run()  // establece la capacidad de modificar a campoIntroducir
  202.             {
  203.                campoIntroducir.setEditable( editable );
  204.             }
  205.  
  206.          }  // fin de la clase interna
  207.  
  208.       ); // fin de la llamada a SwingUtilities.invokeLater
  209.    }
  210.  
  211.    public static void main( String args[] )
  212.    {
  213.       Servidor aplicacion = new Servidor();
  214.       aplicacion.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
  215.       aplicacion.ejecutarServidor();
  216.    }
  217.  
  218. }  // fin de la clase Servidor
  #4 (permalink)  
Antiguo 08/05/2011, 03:46
 
Fecha de Ingreso: mayo-2011
Mensajes: 11
Antigüedad: 13 años
Puntos: 0
Respuesta: Chat en java

Ya lo tenia implementado, pero muchas gracias endgel.
Te comento como lo hice:
- El servidor toma cada cliente como un hilo
- ArrayList de todos los clientes conectados (hilos creados)
- Para la comunicacion seguia pensando en usar el Channel, pero por ahora estoy utilizando los flujos normales de los sockets

Estoy en proceso de depuracion, y ahora mismo los problemas que tengo son con los avisos y mensajes del servidor a el/los clientes.

Muchas gracias de todos modos!
  #5 (permalink)  
Antiguo 08/05/2011, 07:30
Avatar de HackmanC  
Fecha de Ingreso: enero-2008
Ubicación: Guatemala
Mensajes: 1.817
Antigüedad: 16 años, 3 meses
Puntos: 260
Sonrisa Respuesta: Chat en java

Cita:
Iniciado por MjRoxas Ver Mensaje
... Necesito llevar una lista de los conectados: he pensado en la clase DefaultListModel, pero no entiendo muy bien como esta clase mantiene informados al resto de los conectados mediando los metodos de fire..
¿Por qué no usas tu propia implementación? Esta implementación es bastante antigua, así que use un HashSet, pero actualmente podrías usar una implementación como LinkedList. Cada usuario es un JUser y es un Thread, e implementa una función para enviarle mensajes.

Código Java:
Ver original
  1. public class JUser extends JObject implements JPingerListener, JConnectionHandler {
  2. ...
  3.     public void notice(String message) {
  4.         socket.print(JMessage.message(JMessage.JM_NOTICE, nickname, message));
  5.     }
  6.    
  7.     public void noticeWithMode(String message, char mode) {
  8.         if(modes.indexOf(mode) != -1)
  9.             notice(message);
  10.     }
  11. ...    
  12. }

La lista de usuarios, que es un HashSet de JUser se mantiene sincronizada y pasa por cada uno enviandole los mensajes correspondientes a uno y cada uno de los participantes, (cuando escribí esta aplicación no existía los Generics, pero puedes adaptar el método con Generics para no tener la necesidad de hacer el cast a JUser).

Código Java:
Ver original
  1. public class JUsers extends JObject {
  2. ...
  3.     private HashSet users;
  4. ...
  5.     public synchronized void handleConnection(Socket socket) throws IOException {
  6.         JUser user = new JUser(this, socket);
  7.         user.start();
  8.         users.add(user);
  9.     }
  10.    
  11.     public synchronized void remove(JUser user, String message) {
  12.         users.remove(user);
  13.     }
  14. ...
  15.     public synchronized void fireNoticeAll(String message) {
  16.         for(Iterator e = users.iterator(); e.hasNext(); )
  17.             ((JUser)e.next()).notice(message);
  18.     }
  19.    
  20.     public synchronized void fireNoticeAllWithMode(String message, char mode) {
  21.         for(Iterator e = users.iterator(); e.hasNext(); )
  22.             ((JUser)e.next()).noticeWithMode(message, mode);
  23.     }
  24. ...    
  25. }

El servidor cuando necesita avisarle a todos solamente hace uso del método de la clase donde le avisa a todos los usuarios conectados,

Código Java:
Ver original
  1. public class JServer extends JThread {
  2. ...
  3.     public JServer(int port) {
  4.         this.users = new JUsers(this);
  5.     }
  6. ...
  7.     private synchronized void handleConnection(Socket socket) throws IOException {
  8. ...
  9.                     if(!bannedConnection(socket, hostname, hostaddr))
  10. ...
  11.         }
  12.     }
  13. ...
  14.     private boolean bannedConnection(Socket socket, String hostname, String hostaddr) {
  15. ...
  16.         if(banned) {
  17.             JSocket.print(socket, JMessage.message(JMessage.JM_KLINED, kl.reason));
  18.             users.fireNoticeAllWithMode(JMessage.message(JMessage.JM_KLINEDALL, hostname), 'K');
  19. ...
  20.         }
  21.        
  22.         return banned;
  23.     }
  24. }

De esa forma cuando el servidor quiere enviar un mensaje a todos los usuarios, o un usuario quiere enviar un mensaje a todos los demás usuarios, pasa por cada uno de los conectados y les envía el mensaje.

Cita:
Iniciado por MjRoxas Ver Mensaje
... Estoy en proceso de depuracion, y ahora mismo los problemas que tengo son con los avisos y mensajes del servidor a el/los clientes. ...
La programación en Java está orientada a objetos, aunque la aplicación que mostró endgel ha de ser funcional parece programación estructurada, como Pascal o C.

Para hacer este servidor y lograr que todos los componentes se comuniquen correctamente necesitas por lo menos 10 clases distintas, por ejemplo .. JServer, JSocket, JUser, JUsers, JConnection, JConnectionHandler, JChannel, JChannels, etc. Cada uno tiene una ocupación diferente y de esta forma logras dividir la funcionalidad de cada componente para que sea mas fácil de sincronizar al mismo tiempo de mantener la lógica simple.

Saludos,

ps:

El codigo fue escrito en el año 2002, así que evidentemente es muy antiguo, y eliminé muchas partes de control de errores, etc., pero es rápido y eficiente, en lo que cabe con cien usuarios conectados.

Última edición por HackmanC; 08/05/2011 a las 07:49 Razón: año

Etiquetas: chat, defaultlistmodel
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 01:21.