4D 20 R8 introduced the TCPConnection class, bringing an object-oriented, asynchronous way to handle TCP client connections. Then came 4D 20 R9 with the TCPListener class to build TCP servers. And now, with 4D 20 R10, we’re completing the picture with the new UDPSocket class, allowing you to manage UDP communications between 4D and any remote machine, both as a client and a server. This is especially useful for IoT, real-time monitoring, or broadcasting exchanges. And the icing on the cake? This class supports preemptive and asynchronous UDP communication
Finally, this new feature is marking the final step in replacing the legacy Internet Commands plugin.
Let’s dive into the details.
Why UDP?
UDP is a lightweight, connectionless protocol. Unlike TCP, it doesn’t maintain a persistent connection between the two endpoints. There’s no built-in acknowledgment or retransmission mechanism, making it useful for “send and forget” scenarios imposed by third-parties, like IoT, real-time monitoring, or broadcasting.
With the new UDPSocket class, you now have full control over both sending and receiving UDP packets in 4D. The principles presented below are also described in this HDI:
Defining a UDP Client Class
Here’s a simple clientUDP class that handles sending data to a UDP server:
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")
In this example:
- The constructor sets the target IP and port.
- The sendMessage function sends the message passed as a parameter.
- onError and onTerminate handle lifecycle events.
- No onData is needed—UDP clients typically don’t receive responses.
Defining a UDP Server Class
Now let’s look at a serverUDP class that listens for incoming UDP messages:
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")
Here:
- The server listens on the port passed to the constructor.
- The onData callback handles incoming messages. Messages are stored in an instance of the new UDPEvent class.
- As with the client, onError and onTerminate manage lifecycle events.
Running the Server in a Worker
To keep the server running independently, you must launch it in a worker:
CALL WORKER("myServerUDP"; Formula(cs.serverUDP.new(12345)))
Note: The UDP socket is automatically released when there’s no more reference on the object. In this case, stopping the worker will terminate the server.
Sending Data from Client to Server
Once both classes are in place, sending a message is as simple as:
cs.clientUDP.new("127.0.0.1"; 12345).sendMessage("Test message")
UDP communication has never been easier in 4D. With the new UDPSocket class, you can now build lightweight, real-time communication features into your applications—whether you’re sending commands to a device or listening for updates from a remote system.
We hope this new feature opens up exciting possibilities for your projects.
It’s time to get rid of the Internet Commands plugin!
Happy coding!
