Una guía para UDP en Java

1. Información general

En este artículo, exploraremos la comunicación en red con Java, sobre el Protocolo de datagramas de usuario (UDP).

UDP es un protocolo de comunicación que transmite paquetes independientes a través de la red sin garantía de llegada y sin garantía del orden de entrega .

La mayor parte de la comunicación a través de Internet se lleva a cabo a través del Protocolo de control de transmisión (TCP), sin embargo, UDP tiene su lugar que exploraremos en la siguiente sección.

2. ¿Por qué utilizar UDP?

UDP es bastante diferente del TCP más común. Pero antes de considerar las desventajas de UDP a nivel de superficie, es importante comprender que la falta de sobrecarga puede hacerlo significativamente más rápido que TCP.

Además de la velocidad, también debemos recordar que algunos tipos de comunicación no requieren la confiabilidad de TCP, sino que valoran la baja latencia. El video es un buen ejemplo de una aplicación que podría beneficiarse de ejecutarse sobre UDP en lugar de TCP.

3. Creación de aplicaciones UDP

La creación de aplicaciones UDP es muy similar a la creación de un sistema TCP; la única diferencia es que no establecemos una conexión punto a punto entre un cliente y un servidor.

La configuración también es muy sencilla. Java se envía con soporte de red integrado para UDP, que es parte del paquete java.net . Por lo tanto, para llevar a cabo las operaciones de red a través de UDP, sólo tenemos que importar las clases de la java.net paquete: java.net.DatagramSocket y java.net.DatagramPacket .

En las siguientes secciones, aprenderemos cómo diseñar aplicaciones que se comunican a través de UDP; Usaremos el popular protocolo de eco para esta aplicación.

Primero, crearemos un servidor de eco que devuelva cualquier mensaje que se le envíe, luego un cliente de eco que simplemente envía cualquier mensaje arbitrario al servidor y, finalmente, probaremos la aplicación para asegurarnos de que todo funciona bien.

4. El servidor

En la comunicación UDP, un solo mensaje se encapsula en un DatagramPacket que se envía a través de un DatagramSocket .

Comencemos configurando un servidor simple:

public class EchoServer extends Thread { private DatagramSocket socket; private boolean running; private byte[] buf = new byte[256]; public EchoServer() { socket = new DatagramSocket(4445); } public void run() { running = true; while (running) { DatagramPacket packet = new DatagramPacket(buf, buf.length); socket.receive(packet); InetAddress address = packet.getAddress(); int port = packet.getPort(); packet = new DatagramPacket(buf, buf.length, address, port); String received = new String(packet.getData(), 0, packet.getLength()); if (received.equals("end")) { running = false; continue; } socket.send(packet); } socket.close(); } }

Creamos un DatagramSocket global que usaremos para enviar paquetes, una matriz de bytes para envolver nuestros mensajes y una variable de estado llamada en ejecución .

Para simplificar, el servidor está extendiendo Thread , por lo que podemos implementar todo dentro del método de ejecución .

Dentro de la ejecución , creamos un ciclo while que simplemente se ejecuta hasta que la ejecución cambia a falsa por algún error o un mensaje de terminación del cliente.

En la parte superior del ciclo, instanciamos un DatagramPacket para recibir mensajes entrantes.

A continuación, llamamos al método de recepción en el socket. Este método se bloquea hasta que llega un mensaje y lo almacena dentro de la matriz de bytes del DatagramPacket que se le pasa.

Luego de recibir el mensaje, recuperamos la dirección y puerto del cliente, ya que vamos a enviar la respuesta

espalda.

A continuación, creamos un DatagramPacket para enviar un mensaje al cliente. Note la diferencia en la firma con el paquete receptor. Este también requiere la dirección y el puerto del cliente al que enviamos el mensaje.

5. El cliente

Ahora, implementemos un cliente simple para este nuevo servidor:

public class EchoClient { private DatagramSocket socket; private InetAddress address; private byte[] buf; public EchoClient() { socket = new DatagramSocket(); address = InetAddress.getByName("localhost"); } public String sendEcho(String msg) { buf = msg.getBytes(); DatagramPacket packet = new DatagramPacket(buf, buf.length, address, 4445); socket.send(packet); packet = new DatagramPacket(buf, buf.length); socket.receive(packet); String received = new String( packet.getData(), 0, packet.getLength()); return received; } public void close() { socket.close(); } }

El código no es tan diferente al del servidor. Tenemos nuestro DatagramSocket global y la dirección del servidor. Instalamos estos dentro del constructor.

Tenemos un método separado que envía mensajes al servidor y devuelve la respuesta.

Primero convertimos el mensaje de cadena en una matriz de bytes, luego creamos un DatagramPacket para enviar mensajes.

A continuación, enviamos el mensaje. Inmediatamente convertimos el DatagramPacket en uno receptor.

Cuando llega el eco, convertimos los bytes en una cadena y devolvemos la cadena.

6. La prueba

En una clase UDPTest.java , simplemente creamos una prueba para verificar la capacidad de eco de nuestras dos aplicaciones:

public class UDPTest { EchoClient client; @Before public void setup(){ new EchoServer().start(); client = new EchoClient(); } @Test public void whenCanSendAndReceivePacket_thenCorrect() { String echo = client.sendEcho("hello server"); assertEquals("hello server", echo); echo = client.sendEcho("server is working"); assertFalse(echo.equals("hello server")); } @After public void tearDown() { client.sendEcho("end"); client.close(); } }

En la configuración , iniciamos el servidor y también creamos el cliente. Mientras estamos en el método tearDown , enviamos un mensaje de terminación al servidor para que se cierre y al mismo tiempo cerramos el cliente.

7. Conclusión

En este artículo, hemos aprendido sobre el Protocolo de datagramas de usuario y hemos construido con éxito nuestras propias aplicaciones cliente-servidor que se comunican a través de UDP.

Para obtener el código fuente completo de los ejemplos utilizados en este artículo, puede consultar el proyecto GitHub.