In un mondo sempre più connesso, i siti web o le applicazioni IoT devono essere aggiornati in tempo reale.
Un modo per fornire informazioni istantaneamente ai siti è utilizzare il protocollo Websocket, che fornisce un canale di comunicazione full-duplex tra un server e un client. Dalla v20, 4D fornisce i comandi per creare un server Websocket.
Comandi per creare un server Websocket
Per gestire il server Websocket, 4D fornisce due nuove classi:
- La prima gestisce il server stesso, 4D.WebSocketServer
- La seconda gestisce le connessioni websocket: 4D.WebSocketConnection
Per dimostrare questa funzione, creiamo un semplice server di chat!
Prima di utilizzare la classe websocket server, il server web 4D deve essere avviato!
4D.WebSocketServer
Questa classe consente di gestire i diversi eventi che si verificano sul server. Per farlo, è necessario creare una classe con le seguenti funzioni:
- onConnection(), chiamata quando viene richiesta una nuova connessione.
- onOpen(), chiamata quando il server si avvia
- onTerminate(), chiamata quando il server si ferma
- onError(), chiamata quando si verifica un errore.
Nel nostro esempio, dobbiamo innanzitutto gestire la richiesta di connessione. Con la funzione onConnection(), è possibile annullare una connessione restituendo Null o un oggetto che verrà utilizzato per gestire il messaggio inviato o ricevuto. Nell’esempio che segue, restituiamo la classe WSConnectionHandler (descritta nella prossima sezione):
Function onConnection($wss : Object; $param : Object) : Object
// Richiamiamo il metodo VerifyAddress per verificare se l'indirizzo remoto è autorizzato a connettersi
If (VerifyAddress($param.request.remoteAddress))
// La connessione è consentita
// L'oggetto WSConnectionHandler restituito viene utilizzato
// da 4D per istanziare l'oggetto 4D.WebSocketConnection
// relativo a questa connessione
return cs.WSConnectionHandler.new()
Else
// La connessione viene annullata
return Null
End if
Ora vogliamo registrare l’avvio, la chiusura e gli errori, quindi creiamo una classe WSServerHandler:
Costruttore della classe
Function onOpen($wss : Object; $param : Object)
LogFile("*** Server started")
Function onTerminate($wss : Object; $param : Object)
LogFile("*** Server closed")
Function onError($wss : Object; $param : Object)
LogFile("!!! Server error: "+$param.statusText)
4D.WebSocketConnection
Questa classe consente di gestire diversi eventi durante una determinata connessione. Per farlo, è necessario creare una classe con le funzioni seguenti:
- onMessage(), chiamata ogni volta che arriva un messaggio attraverso questa connessione.
- onOpen(), chiamata quando viene creato l’oggetto 4D.WebSocketConnection
- onTerminate(), chiamata quando l’oggetto 4D.WebSocketConnection viene terminato
- onError(), chiamata quando si verifica un errore
Per la nostra chat, questa classe sarà la classe WSConnectionHandler. Essa:
- avvisa gli altri utenti che un nuovo utente si è connesso quando viene aperta la connessione
- avvisa gli altri utenti che un utente si è disconnesso quando la connessione viene terminata
- trasmette i messaggi ricevuti a tutti gli altri client di chat connessi quando viene ricevuto un messaggio.
Function onMessage($ws : 4D.WebSocketConnection; $messaggio : Object)
// reinvio del messaggio a tutti i client di chat
This.broadcast($ws;$messaggio.dati)
Function onOpen($ws : 4D.WebSocketConnection; $messaggio : Object)
// Invia un messaggio al nuovo utente connesso
$ws.send("Welcome on the chat!")
// Invia il messaggio "New client connected" a tutti gli altri client di chat
This.broadcast($ws; "New client connected")
Function onTerminate($ws : 4D.WebSocketConnection; $message : Object)
// Invia il messaggio "Client disconnesso" a tutti gli altri client di chat
This.broadcast($ws; "Client disconnesso")
Function broadcast($ws : 4D.WebSocketConnection; $message : Text)
var $client:4D.WebSocketConnection
// reinvia il messaggio a tutti i client della chat
For each ($client; $ws.wss.connections)
// Verifica che l'id non sia la connessione corrente
If ($client.id#$ws.id)
$client.send($messaggio)
End if
End for each
Non resta che avviare il server websocket utilizzando le classi create in precedenza. Un server websocket deve essere avviato in un worker, quindi creiamo un nuovo processo con il comando CALL WORKER e vi istanziamo il 4D.WebSocketServer:
var $handler:cs.WSSHandler
$handler:=cs.WSServerHandler.new()
CALL WORKER("WebSocketServer"; Formula(WSS:=4D.WebSocketServer.new($handler))
//Assegnare una variabile (WSS) al WebSocket permette di chiamare WSS.terminate() in seguito
Il server websocket creato esisterà fino a quando il worker non verrà ucciso o verrà richiamata la funzione .terminate().
CALL WORKER("WebSocketServer"; Formula(WSS.terminate()))
Lato client
Di seguito è riportato un esempio di codice in HTML e Javascript per creare un’interfaccia di chat:
Questo codice è progettato per funzionare con un server web locale sulla porta HTTP 80 (riga 18: const urlwss=”ws://127.0.0.1:80/”;).
Per maggiori dettagli, date un’occhiata a questa funzione con l’HDI qui sopra e alla documentazione!