In 4D 20 R8 abbiamo introdotto la classe TCPConnection, che consente di avviare connessioni TCP a server remoti. Con 4D v20 R9, siamo lieti di presentare la classe TCPListener, la chiave per gestire le connessioni TCP in arrivo e costruire un server TCP direttamente in 4D.
Con queste due classi, TCPConnection e TCPListener, avete ora il pieno controllo sulla comunicazione TCP, sia lato client che lato server.
Vediamo come utilizzarle insieme.
Prima di immergerci in questo post, vi consigliamo di dare un’occhiata al nostro precedente post sulla classe TCPConnection per comprendere le basi su cui stiamo costruendo.
Come interagiscono le classi TCPListener e TCPConnection
Definizione della classe Connection
Creeremo una nuova classe chiamata ServerSideConnection, sul modello della classe ConnectionToTheServer usata nell’esempio precedente. Ecco una descrizione dei principali callback da implementare:
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")
Questa classe è una shell semplice che reagisce ai principali eventi TCP.
Impostazione della classe ascoltatore
Ora, creiamo una classe ServerListener per ascoltare su una porta specifica e accettare le connessioni in arrivo:
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")
Per avviare l’ascoltatore, utilizzare:
cs.ServerListener.me.startListening($port)
Ogni volta che un client tenta di connettersi, viene attivato il metodo onConnection. Si può restituire un oggetto ServerSideConnection per accettare la connessione o null per rifiutarla. Una volta accettata, vengono attivati i callback TCPConnection corrispondenti, che consentono di gestire la connessione come qualsiasi altro client.
Per interrompere l’ascolto di nuove connessioni, basta chiamare:
cs.ServerListener.me.stopListening()
Nota: le connessioni attive rimangono attive finché non vengono chiuse manualmente.
Struttura di classe unificata = codice semplificato
Uno dei principali vantaggi di questa struttura è che la stessa classe TCPConnection viene utilizzata sia per le connessioni client che per quelle server. Questa simmetria semplifica l’implementazione e favorisce il riutilizzo del codice, poiché il comportamento di entrambe le estremità della connessione può condividere la stessa logica e struttura.
Conclusione
Con l’aggiunta della classe TCPListener in 4D v20 R9, è ora possibile creare robusti server TCP interamente in 4D. Insieme a TCPConnection, i nuovi strumenti offrono un quadro completo per la gestione della comunicazione TCP bidirezionale, in modo pulito, efficiente e con una duplicazione minima del codice.
Se avete domande o commenti, non esitate a farli sul forum di 4D.