In 4D 20 R8, we introduced the TCPConnection class, allowing you to initiate TCP connections to remote servers. With 4D v20 R9, we’re excited to bring you the TCPListener class—your key to handling incoming TCP connections and building a TCP server directly in 4D.
With these two classes—TCPConnection and TCPListener—you now have full control over TCP communication, both client- and server-side.
Let’s walk through how to use them together.
Before diving into this post, we highly recommend checking out our previous blog post on the TCPConnection class to understand the foundation we’re building on.
How the TCPListener and TCPConnection classes interact
Defining The connection class
We’ll create a new class called ServerSideConnection, modeled after the ConnectionToTheServer class used in the previous example. Here’s a breakdown of the key callbacks you’ll implement:
Class constructor()
//Callback called when the connection is successfully established
Function onConnection($connection : 4D.TCPConnection; $event : 4D.TCPEvent)
ALERT("Connection established")
//Callback called when the connection is properly closed
Function onShutdown($connection : 4D.TCPConnection; $event : 4D.TCPEvent)
ALERT("Connection closed")
//Callback called when receiving data. The simple servers always send a sentence to show to the user
Function onData($connection : 4D.TCPConnection; $event : 4D.TCPEvent)
ALERT(BLOB to text($event.data; UTF8 text without length))
//Callback called when the connection is closed unexpectedly
Function onError($connection : 4D.TCPConnection; $event : 4D.TCPEvent)
ALERT("Connection error")
This class is a straightforward shell that reacts to key TCP events.
Setting Up The listener class
Now, let’s create a ServerListener class to listen on a specific port and accept incoming connections:
property listener:4D.TCPListener
shared singleton Class constructor()
//Start listening to the port given as parameter
shared Function startListening($port:integer)
This.listener:=4D.TCPListener.new($port, This)
//Stop listening
shared Function stopListening()
This.listener.terminate()
//Callback called on a new incoming connection
Function onConnection($listener : 4D.TCPListener; $event : 4D.TCPEvent)->$result
ALERT("Listener: onConnection")
if ($event.IP = "a good IP address")
$result:=cs.ServerSideConnection.new()
else
$result := null
end if
//Callback called when an error prevents listening on the port (in general due to conflict with another application)
Function onError($listener : 4D.TCPListener; $event : 4D.TCPEvent)
ALERT("Listener: onError")
To start the listener, use:
cs.ServerListener.me.startListening($port)
Every time a client attempts to connect, the onConnection method is triggered. You can return a ServerSideConnection object to accept the connection—or return null to reject it. Once accepted, the corresponding TCPConnection callbacks kick in, allowing you to handle the connection like any other client.
To stop listening for new connections, just call:
cs.ServerListener.me.stopListening()
Note: Active connections will remain until you close them manually.
Unified Class Structure = Simplified Code
A major benefit of this design is that the same TCPConnection class is used for both client and server connections. This symmetry simplifies your implementation and promotes code reuse, as the behavior for both ends of the connection can share the same logic and structure.
Conclusion
With the addition of the TCPListener class in 4D v20 R9, you can now create robust TCP servers entirely in 4D. Paired with TCPConnection, the new tools give you a complete framework for handling two-way TCP communication—cleanly, efficiently, and with minimal code duplication.
If you have any question or feedback, don’t hesitate to bring them on the 4D forum.