4D 20 R8 introdujo la clase TCPConnection, aportando una forma asíncrona y orientada a objetos de manejar las conexiones de clientes TCP. Luego vino 4D 20 R9 con la clase TCPListener para construir servidores TCP. Y ahora, con 4D 20 R10, estamos completando el cuadro con la nueva clase UDPSocket, que le permite gestionar las comunicaciones UDP entre 4D y cualquier máquina remota, tanto como cliente como servidor. Esto es especialmente útil para IoT, monitorización en tiempo real o intercambios de difusión. ¿Y la cereza del pastel? Esta clase soporta comunicación UDP preventiva y asíncrona.
Por último, esta nueva funcionalidad está marcando el paso final en la sustitución del plugin de comandos de Internet heredado.
Profundicemos en los detalles.
¿Por qué UDP?
UDP es un protocolo ligero y sin conexión. A diferencia de TCP, no mantiene una conexión persistente entre los dos extremos. No lleva intregrado ningún mecanismo de acuse de recibo o retransmisión, lo que lo hace útil para escenarios de «enviar y olvidar» impuestos por terceros, como IoT, monitorización en tiempo real o radiodifusión.
Con la nueva clase UDPSocket, ahora tiene control total sobre el envío y recepción de paquetes UDP en 4D. Los principios presentados a continuación también se describen en este HDI:
Definición de una Clase Cliente UDP
He aquí una simple clase clienteUDP que maneja el envío de datos a un servidor UDP:
property socket : 4D.UDPSocket
property ip : Text
property port : Integer
Class constructor ($ip: Text; $port: Integer)
This .socket:=4D.UDPSocket.new(0; This)
This .ip:=$ip
This .port:=$port
//Send message to the UDP server
Function sendMessage ($message: Text)
var $blob : Blob
TEXT TO BLOB ($message; $blob; UTF8 text without length)
This .socket.send($blob; This.ip; This.port)
//Callback called when the socket is closed unexpectedly
Function onError ($socket: 4D.UDPSocket; $event: 4D.UDPEvent)
ALERT ("clientUDP instance error")
//Callback called after onShutdown/onError just before the UDPSocket object is released
Function onTerminate($socket : 4D.UDPSocket; $event : 4D.UDPEvent)
ALERT ("clientUDP instance termination")
En este ejemplo:
- El constructor define la IP y el puerto de destino.
- La función sendMessage envía el mensaje pasado en parámetro.
- onError y onTerminate manejan los eventos del ciclo de vida.
- No es necesario onData: los clientes UDP normalmente no reciben respuestas.
Definiendo una Clase Servidor UDP
Ahora veamos una clase serverUDP que escucha los mensajes UDP entrantes:
property socket 4D .UDPSocket
//The constructor creates a UDPSocket to listen to the port given in parameter
Class constructor ($port: Integer)
This .socket:=4D.UDPSocket.new($port; This)
//Callback called when receiving data
Function onData ($socket: 4D.UDPSocket; $event: 4D.UDPEvent)
var $data :=BLOB to text($event.data; UTF8 text without length)
ALERT ("serverUDP instance: Received message:\r\n "+$data)
//Callback called when the connection is closed unexpectedly
Function onError ($socket: 4D.UDPSocket; $event: 4D.UDPEvent)
ALERT ("serverUDP instance: error\r\n "+JSON Stringify($event.data; *))
//Callback called after onShutdown/onError just before the UDPSocket object is released
Function onTerminate ($socket: 4D.UDPSocket; $event: 4D.UDPEvent)
ALERT ("serverUDP instance: Server termination")
Aquí:
- El servidor escucha en el puerto dado como parámetro del constructor.
- La llamada de retorno onData gestiona los mensajes entrantes. Los mensajes se almacenan en una instancia de la nueva clase UDPEvent.
- Al igual que con el cliente, onError y onTerminate gestionan los eventos del ciclo de vida.
Ejecutar el Servidor en un Worker
Para mantener el servidor funcionando de forma independiente, debe lanzarlo en un worker:
CALL WORKER("miServidorUDP"; Formula(cs.serverUDP.new(12345)))
Nota: el socket UDP se libera automáticamente cuando no hay más referencia en el objeto. En este caso, al detener el worker se terminará el servidor.
Envío de datos del cliente al servidor
Una vez que ambas clases están en su lugar, enviar un mensaje es tan simple como:
cs.clientUDP.new("127.0.0.1"; 12345).sendMessage("Mensaje de prueba")
La comunicación UDP nunca ha sido tan fácil en 4D. Con la nueva clase UDPSocket, ahora puede construir funciones de comunicación ligeras y en tiempo real en sus aplicaciones, ya sea que esté enviando comandos a un dispositivo o escuchando actualizaciones de un sistema remoto.
Esperamos que esta nueva función abra interesantes posibilidades para sus proyectos.
Es hora de deshacerse del plugin Internet Commands.
¡Feliz programación!
