Eco cliente-servidor con sockets UDP en Java (DatagramSocket)

Informática y TelecomunicacionesActualizado el 6,07 KB

Resumen

El documento explica cómo implementar un sistema de comunicación de eco entre un cliente y un servidor usando el protocolo UDP y la clase DatagramSocket de Java. Se presentan el código del cliente, que envía mensajes y espera la respuesta hasta recibir "fin", y el del servidor, que escucha en bucle infinito y devuelve cada mensaje recibido.

Puntos clave

  • UDP es un protocolo sin conexión que se gestiona en Java con DatagramSocket y DatagramPacket.
  • El cliente crea un DatagramSocket sin argumentos, envía un datagrama a la IP y puerto del servidor y espera la respuesta.
  • El cliente termina la comunicación al escribir "fin", cerrando el socket.
  • El servidor se enlaza a una dirección con InetSocketAddress y permanece en un bucle infinito recibiendo y reenviando datagramas.
  • Para construir el String recibido se usa la longitud real del paquete (getLength()) en lugar de la longitud del buffer.

Ponte a prueba

Ejercicio 3: Comunicación Cliente-Servidor mediante UDP

Este documento presenta la implementación en Java de un sistema de comunicación de eco (echo) utilizando el protocolo UDP a través de la clase DatagramSocket.

1. Clase Cliente

El cliente se encarga de enviar mensajes al servidor y esperar la respuesta de eco, cerrando la conexión al enviar el mensaje "fin".

Código Java del Cliente


public class Cliente {

    // Se asume que este código se ejecuta dentro de un método main o similar
    public static void main(String[] args) {

        try { 
            // Le pasamos la IP y el puerto de conexión, y el bind se realiza de forma implícita:
            InetAddress addr = InetAddress.getByName(HOST); // Crea la InetAddress
            DatagramSocket ds = new DatagramSocket(); // Crea el socket
            Scanner scanner = new Scanner(System.in);
            String mensaje;

            do {
                System.out.print("Escriba el mensaje que desea enviar al servidor: ");
                mensaje = scanner.next(); // Escribimos el mensaje que deseamos enviar

                // DatagramPacket datagrama = new DatagramPacket(mensaje, longitud); // Datagrama que se usa para recibir

                // Datagrama que se usa para enviar
                DatagramPacket datagramaEnviar = new DatagramPacket(
                    mensaje.getBytes(),
                    mensaje.getBytes().length, 
                    addr, 
                    PUERTO
                ); // Crea el datagrama 

                ds.send(datagramaEnviar); // Se envía el datagrama

                // Para recibir el mensaje
                int longitud = 100; // Longitud máxima del mensaje
                byte[] mensajeRecibido = new byte[longitud]; // Array de bytes donde almacenar el mensaje
                DatagramPacket datagramaRecibir = new DatagramPacket(mensajeRecibido, longitud);

                ds.receive(datagramaRecibir);

                if (mensaje.equalsIgnoreCase("fin")) {
                    System.out.println("FIN DE COMUNICACIÓN :)");
                    ds.close();
                } else {
                    // Se utiliza la longitud real del paquete recibido para construir el String
                    String ecoMensaje = new String(datagramaRecibir.getData(), 0, datagramaRecibir.getLength()).trim();
                    System.out.println(">>ECO: " + ecoMensaje);
                }

            } while (!mensaje.equalsIgnoreCase("fin"));

            scanner.close();

        } catch (IOException e) {
            System.err.println("Error al conectarse con el socket del servidor.");
            System.out.println(e.getMessage()); // Ejemplo: Connection refused: connect
        }
    }
}

2. Clase Servidor

El servidor se mantiene en un bucle infinito, esperando peticiones de clientes, recibiendo el mensaje y enviándolo de vuelta como eco.

Código Java del Servidor


public class Servidor {

    public static void main(String[] args) {

        try {
            System.out.println("Esperando una petición del socket cliente...");

            // Le pasamos la IP y el puerto de conexión, y el bind se realiza de forma implícita:
            InetSocketAddress addr = new InetSocketAddress(HOST, PUERTO); // Incluye el bind

            // Nota: InetSocketAddress en el servidor se usa porque es como abrir una puerta con una dirección a la que los clientes se conectan.
            DatagramSocket ds = new DatagramSocket(addr); // Crea el socket

            while(true) {
                int longitud = 100; // Longitud máxima del mensaje
                byte[] mensaje = new byte[longitud]; // Array de bytes donde almacenar el mensaje

                // Recibe el mensaje del cliente
                DatagramPacket datagrama = new DatagramPacket(mensaje, longitud); // Se crea el datagrama
                ds.receive(datagrama); // Se carga en el datagrama el mensaje recibido

                // Se puede reutilizar el Datagrama, y en receive se puede usar datagrama.getData()
                // Lo convierto a String, usando la longitud real del paquete recibido
                String mensajeRecibido = new String(datagrama.getData(), 0, datagrama.getLength()).trim();

                // Para enviar de vuelta lo que recibo (Eco)
                System.out.println("Mensaje recibido: " + mensajeRecibido );

                // Envía el datagrama (que ahora contiene la dirección de retorno del cliente)
                ds.send(datagrama);

                if(mensajeRecibido.equalsIgnoreCase("fin")) { 
                    // Nota: En UDP, el servidor generalmente sigue escuchando, a menos que se fuerce el cierre.
                    System.out.println("Cliente ha enviado 'fin'. El servidor sigue activo.");
                    // ds.close(); // Cierra la conexión si se desea terminar el servidor
                }
            }
        } catch (IOException e) {
            System.err.println("Error al crear el socket del servidor.");
            e.printStackTrace();
        }
    }
}

Descargar

PDF Word HTML

Preguntas frecuentes

¿Qué clase se usa para comunicar con UDP en Java?

En el documento se usa DatagramSocket para enviar y recibir, y DatagramPacket para encapsular los datos junto con la dirección y el puerto.

¿Cómo sabe el servidor a qué cliente responder?

Al recibir el datagrama, este contiene la dirección y el puerto de origen del cliente, por lo que el servidor puede reenviarlo directamente con ds.send(datagrama).

¿Por qué se usa getLength() al convertir el mensaje a String?

Porque el buffer tiene una longitud fija de 100 bytes y getLength() indica cuántos bytes contiene realmente el paquete recibido, evitando datos sobrantes.

Ponte a prueba

Tarjetas de repaso

Pulsa una tarjeta para ver la respuesta.

Test

1. ¿Qué clase de Java se utiliza para enviar y recibir datagramas UDP en el ejemplo?
2. ¿Qué mensaje hace que el cliente cierre la comunicación?
3. ¿Qué hace el servidor al recibir un mensaje?
4. ¿Qué tamaño tiene el buffer de recepción en el código del cliente y el servidor?
5. ¿Cuándo termina el bucle del servidor en el código presentado?

Preguntas generadas con IA a partir del documento: comprueba las respuestas con el texto.