Che cosa sono i Websockets?

Negli ultimi anni, un nuovo tipo di comunicazione ha iniziato ad emergere sul web e nelle app mobili, chiamato websockets. Questo protocollo è stato a lungo atteso ed è stato finalmente standardizzato dall’IETF nel 2011, aprendo la strada ad un uso diffuso.

Questo nuovo protocollo apre una linea di comunicazione molto più veloce ed efficiente per il client. Come HTTP, i websockets funzionano su una connessione TCP, ma sono molto più veloci perché non dobbiamo aprire una nuova connessione ogni volta che vogliamo inviare un messaggio, dato che la connessione viene mantenuta in vita per tutto il tempo che il server o il client desiderano.

Ancora meglio, dato che la connessione non muore mai, abbiamo finalmente a disposizione una comunicazione full-duplex, il che significa che possiamo inviare dati al client invece di dover aspettare che sia lui a chiedere dati al server. Questo permette ai dati di essere comunicati avanti e indietro, il che è ideale per cose come applicazioni di chat in tempo reale, o anche giochi.

Come funzionano i websockets?

Al suo interno, un websocket è solo una connessione TCP che permette la comunicazione full-duplex, il che significa che entrambi i lati della connessione possono inviare dati all’altro, anche allo stesso tempo.

Per stabilire questa connessione, il protocollo inizia effettivamente l’handshake come una normale richiesta HTTP, ma poi viene ‘aggiornato’ utilizzando l’intestazione HTTP di richiesta di aggiornamento, in questo modo:

Il server invia quindi una risposta HTTP 101 “Switching Protocols”, riconoscendo che la connessione sta per essere aggiornata. Una volta che questa connessione è stata fatta, passa a un protocollo binario bidirezionale, a quel punto i dati dell’applicazione possono essere inviati.

Tutto ciò che il protocollo deve fare per mantenere aperta la connessione è inviare alcuni pacchetti ping/pong, che dicono all’altra parte che sono ancora lì. Per chiudere la connessione, viene inviato un semplice pacchetto “close connection”.

Alcuni esempi di websocket

Tra le molte librerie websocket per Node.js disponibili, ho scelto di usare socket.io in questo articolo perché sembra essere la più popolare ed è, a mio parere, la più facile da usare. Mentre ogni libreria ha la sua API unica, hanno anche molte somiglianze, dato che sono tutte costruite sullo stesso protocollo, quindi si spera che sarete in grado di tradurre il codice qui sotto a qualsiasi libreria vogliate usare.

Per il server HTTP, userò Express, che è il server Node più popolare là fuori. Tenete a mente che potete anche usare il semplice modulo http se non avete bisogno di tutte le caratteristiche di Express. Anche se, dato che la maggior parte delle applicazioni userà Express, è quello che useremo anche noi.

Nota: In tutti questi esempi ho rimosso molto del codice boilerplate, quindi parte di questo codice non funzionerà fuori dalla scatola. Nella maggior parte dei casi potete fare riferimento al primo esempio per ottenere il codice di base.

Stabilire la connessione

Per stabilire una connessione tra client e server, il server deve fare due cose:

  1. Agganciarsi al server HTTP per gestire le connessioni websocket
  2. Servire la socket.io.js libreria client come risorsa statica

Nel codice che segue, potete vedere che il punto (1) viene fatto sulla terza linea. Il punto (2) è fatto per voi (di default) dalla libreria socket.io e viene servito nel percorso https://stackabuse.com/socket.io/socket.io.js. Per impostazione predefinita, tutte le connessioni websocket e le risorse sono servite nel percorso /socket.io.

Server

Anche il client deve fare due cose:

  1. Caricare la libreria dal server
  2. Chiamare .connect() l’indirizzo del server e il percorso del websocket

Client

<script src="https://stackabuse.com/socket.io/socket.io.js"></script><script> var socket = io.connect('/');</script>

Se si naviga con il browser verso e si ispezionano le richieste HTTP dietro le quinte usando gli strumenti di sviluppo del browser, dovreste essere in grado di vedere l’esecuzione dell’handshake, incluse le richieste GET e la conseguente risposta HTTP 101 Switching Protocols.

Invio di dati dal server al client

Ok, ora passiamo ad alcune delle parti più interessanti. In questo esempio vi mostreremo il modo più comune per inviare dati dal server al client. In questo caso, invieremo un messaggio ad un canale, che può essere sottoscritto e ricevuto dal client. Così, per esempio, un’applicazione client potrebbe essere in ascolto sul canale ‘annunci’, che conterrebbe notifiche su eventi a livello di sistema, come quando un utente si unisce a una chat room.

Sul server questo viene fatto aspettando che la nuova connessione sia stabilita, poi chiamando il metodo socket.emit() per inviare un messaggio a tutti i client connessi.

Server

io.on('connection', function(socket) { socket.emit('announcements', { message: 'A new user has joined!' });});

Client

Invio di dati da client a server

Ma cosa facciamo quando vogliamo inviare dati nell’altro senso, da client a server? È molto simile all’ultimo esempio, usando entrambi i metodi socket.emit() e socket.on().

Server

Client

Conteggio degli utenti connessi

Questo è un bell’esempio da imparare poiché mostra alcune caratteristiche in più del socket.io (come l’evento disconnect), è facile da implementare ed è applicabile a molte webapp. Useremo gli eventi connection e disconnect per contare il numero di utenti attivi sul nostro sito, e aggiorneremo tutti gli utenti con il conteggio attuale.

Server

Client

Un modo molto più semplice per tracciare il conteggio degli utenti sul server sarebbe quello di usare semplicemente questo:

var numClients = io.sockets.clients().length;

Ma apparentemente ci sono alcuni problemi relativi a questo, quindi potresti dover tenere traccia del conteggio del client da solo.

Camere e spazi dei nomi

È probabile che, man mano che la vostra applicazione cresce in complessità, abbiate bisogno di maggiore personalizzazione con i vostri websockets, come inviare messaggi a un utente specifico o a un insieme di utenti. O forse volete una rigida separazione della logica tra le diverse parti della vostra applicazione. È qui che entrano in gioco le stanze e i namespace.

Nota: Queste caratteristiche non fanno parte del protocollo websocket, ma sono state aggiunte da socket.io.

Di default, socket.io usa il namespace root (/) per inviare e ricevere dati. Programmaticamente, è possibile accedere a questo spazio dei nomi tramite io.sockets, anche se molti dei suoi metodi hanno scorciatoie su io. Quindi queste due chiamate sono equivalenti:

io.sockets.emit('stats', { data: 'some data' });io.emit('stats', { data: 'some data' });

Per creare il proprio namespace, tutto quello che dovete fare è quanto segue:

Inoltre, il client deve connettersi al vostro namespace esplicitamente:

<script src="https://stackabuse.com/socket.io/socket.io.js"></script><script> var socket = io('/stackabuse');</script>

Ora qualsiasi dato inviato all’interno di questo namespace sarà separato dal namespace predefinito /, indipendentemente dal canale utilizzato.

Andando ancora oltre, all’interno di ogni namespace è possibile unire e lasciare delle “stanze”. Queste stanze forniscono un altro livello di separazione in cima ai namespace, e poiché un client può essere aggiunto ad una stanza solo dal lato server, forniscono anche un po’ di sicurezza in più. Quindi, se volete essere sicuri che gli utenti non stiano curiosando su certi dati, potete usare una stanza per nasconderli.

Per essere aggiunto a una stanza, devi .join() it:

io.on('connection', function(socket){ socket.join('private-message-room');});

Da lì puoi inviare messaggi a tutti quelli che appartengono alla stanza data:

io.to('private-message-room').emit('some event');

E infine, chiama .leave() per smettere di ricevere messaggi di eventi da una stanza:

socket.leave('private-message-room');

Conclusione

Questa è solo una libreria che implementa il protocollo websockets, e ce ne sono molte altre là fuori, tutte con le loro caratteristiche e punti di forza unici. Ti consiglio di provare alcune delle altre (come node-websockets) in modo da farti un’idea di quello che c’è là fuori.

In poche righe, puoi creare delle applicazioni piuttosto potenti, quindi sono curioso di vedere cosa puoi inventare!

Categorie: Articles

0 commenti

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *