Introduzione ai WebSocket

4 febbraio 2013

Questo articolo è la traduzione di “WebSockets: A Guide”, di Jack Lawson e pubblicato su buildnewgames.com. Con l’approvazione di Microsoft.

I WebSockets forniscono una comunicazione bidirezionale in tempo reale tra client e server, e quindi sono estremamente utili nella costruzione dei moderni web games. I giochi browser-based possono sfruttare connessioni a bassa latenza e always-on, per la trasmissione rapida di informazioni sullo stato dei giocatori e del gioco intero in un modo precedentemente solo emulato da metodi come polling Ajax e Comet. È utile considerare in primis la storia di WebSockets e comprendere come funziona a livello tecnico, prima di esaminare come possiamo usare WebSockets in modo più efficace. Armati di questa conoscenza, possiamo semplificare il livello di rete e creare giochi incredibilmente reattivi che forniscono un elevato livello di interazioni multiplayer.

Storia

Internet è stata sviluppata (per semplificare grossolanamente) come un modo per consentire alle organizzazioni di condividere informazioni in modo efficiente e senza ritardi. L’informazione su Internet viene trasportata attraverso una suite di protocolli di connessione chiamato TCP/IP, che definisce il metodo il quale fare condividere le informazioni tra computer in una rete decentralizzata con una ragionevole certezza sul loro arrivo a destinazione.

TCP/IP correla il messaggio di informazioni, come l’origine e la destinazione. Il messaggio contiene un checksum (un valore calcolato a partire dai dati stessi) che può essere utilizzato dal ricevente per verificare se tutte le informazioni siano state ricevute correttamente.

La diffusione della “rete” come sappiamo è passata attraverso il protocollo HTTP, che fornisce un livello di astrazione che impacchetta le connessioni TCP/IP in un involucro contenente informazioni relative alla richiesta, nonché i dati per la richiesta stessa, come ad esempio i campi dei form e i valori dei cookie. Questo strato HTTP fornisce una semplice interfaccia di richiesta e risposta che funziona bene per azioni come ottenere una pagina web, caricamre un’immagine, o passare dati a un server per la persistenza.

Nell’evoluzione che ha avuto lo sviluppo di applicazioni web dal 2004 in poi, Ajax è diventato un metodo estremamente utile attraverso il quale recuperare i dati da un server. Ajax è un’interfaccia attraverso la quale javascript può creare una richiesta HTTP e gestire la risposta in modo asincrono con una funzione di callback in caso di successo o il fallimento.

Laddove gli utenti precedentemente dovevano aggiornare o cambiare pagina per visualizzare il contenuto aggiornato, con poco codice JavaScript si può effettuare la richesta al server, ottenere dati aggiornati, e visualizzare i dati nella pagina, per applicazioni che rispondano senza più soluzione di continuità. Gmail, Facebook e Twitter sono tutti esempi considerevoli di di “single-page-apps”, che prelevano i dati tramite chiamate al server che avvegono dietro le quinte, permettendo all’utente un flusso di lavoro più agevole. HTTP è rimasto invariato dal 1999, supportando la trasmissione di questi pacchetti attraverso connessioni usa e getta.

Seguendo l’evoluzione delle applicazioni web, è cresciuta anche la necessità di una comunicazione in tempo reale. Le applicazioni di chat, i giochi online e i sistemi di notifica si basano su un abuso del protocollo HTTP attraverso sistemi come polling Ajax, connessioni persistenti HTTP Comet, aprendo iframe per effettuare il polling di nuovi dati dal server o utilizzando Flash per il livello di rete o per costruire tutta l’applicazione. Anche se evoluti, questi metodi avevano aspetti negativi come inefficienze o complessità. Eppure la risposta era proprio sotto il naso del protocollo HTTP: la stessa connessione TCP che sottende l’HTTP poteva essere utilissata per collegamenti a doppio senso, persistenti ed efficienti, direttamente tra client (browser) e server web.

La specifica WebSocket è stata completata in un momento fantastico nell’era dello sviluppo di applicazioni web: insieme all’avvento di HTML5 e di una pletora di tecnologie ad esso correlate per l’open web. Ora è una specifica stabile e supportato da browser moderni come Chrome, Firefox e Internet Explorer 10.

La connessione continua TCP consente agli sviluppatori di realizzare giochi online molto reattivi e connessi in modo molto più efficiente, sia per l’utilizzo delle risorse di client e server sia in fase di sviluppo, utilizzando un flusso “nativo” invece di un sistema di interrogazione a polling.

Con i WebSocket, se un utente muove il proprio personaggio del gioco, in pochi millisecondi un altro utente vedrà muoversi il personaggio sul proprio schermo. Inoltre un giocatore può chattare sapendo che i suoi messaggi appaiono istantaneamente nel gioco, un carro armato può sparare un colpo, e il vettore può essere tracciato in tempo reale su due schermi contemporaneamente. Tutto questo può essere costruito con tecnologie open web.

Un WebSocket visti da vicino

Parleremo del modello RFC6455 (hybi-17), che ha alcune differenze rispetto a implementazioni precedenti. Poiché questo è lo standard ufficiale, non staremo a discutere le differenze.

Tecnicamente parlando, un WebSocket è una connessione TCP persistente, bi-direzionale full-duplex, garantita da un sistema di handshaking client-key ed un modello di sicurezza origin-based. Il sistema inotre maschera le trasmissioni dati per evitare lo sniffing di pacchetti di testo in chiaro.

Vediamo cosa significa questa definizione punto per punto:

CaratteristicaDescrizione
Bi-directionalil client è connesso al server, e il server è connesso al client. Ciascuno può ricevere eventi come collegato e scollegato e possono inviare dati all’altro.
Full duplexil server e il client può inviare dati nello stesso momento senza collisioni.
TCPProtocollo sottostante tutte le comunicazioni Internet, che fornisce un meccanismo affidabile per trasportare un flusso di byte da un’applicazione all’altra.
Client-key handshakeil client invia al server una chiave segreta di 16 byte con codifica base64. Il server poi aggiunge una stringa (anche detta “magic string” e specificata nel protocollo come “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”) e rimanda il risultato, elaborato con SHA1, al client. In questo modo, il client può essere certo che il server cui aveva inviato la sua chiave è lo stesso che apre la connessione.
Sicurezza origin-basedL’origine della richiesta WebSocket viene verificata dal server per determinare che provenga da un dominio autorizzato. Il server può rifiutare le connessioni socket da domini non attendibili.
Trasmissione dati mascherataIl cliente inva una chiave di 4 byte per l’offuscamento nella trama iniziale di ogni messaggio. Essa è utilizzata per effettuare uno XOR bit a bit tra dati e chiave. Ciò aiuta a prevenire lo sniffing di dati This helps to prevent data sniffing, poiché un malintenzionato dovrebbe essere capace di determinare il byte di inizio del messaggio per poterlo decrittare.

L’RFC definisce un frame WebSocket come segue:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
|N|V|V|V|       |S|             |   (if payload len==126/127)   |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|     Extended payload length continued, if payload len == 127  |
+ - - - - - - - - - - - - - - - +-------------------------------+
|                               |Masking-key, if MASK set to 1  |
+-------------------------------+-------------------------------+
| Masking-key (continued)       |          Payload Data         |
+-------------------------------- - - - - - - - - - - - - - - - +
:                     Payload Data continued ...                :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|                     Payload Data continued ...                |
+---------------------------------------------------------------+

Il frame dati è abbastanza semplice: contiene informazioni sullo stao di un particolare frame, la lunghezza del contenuto, la masking-key e i dati veri e propri.

Iniziano dall’alto e da sinistra verso destra abbiamo:

BitDescrizione
Fin (bit 0)serve ad indicare l’ultimo frame del messaggio, sarà quindi impostato a 1 quando il frame è l’ultimo di una serie, oppure se il messaggio è composto da un singolo frame (in quanto primo e ultimo della serie)
RSV1, RSV2, RSV3 (bits 1-3)questi tre bit sono riservati alle estensioni dei websoket e dovrebbero essere 0 a meno che ne sia richiesto l’uso da parte di una specifica estensione
Opcode (bits 4-7)questi quattro bit determinano la tipologia di frame. I frame di controllo comunicano lo stato del WebSoket, mentre gli altri trasportano dati. Le diverse tipologie ti codici includono:
  • 0x0continuation frame, contiene dati che devono essere messi in coda al frame precedente
  • 0x1text frame, questo frame, ed eventuali successivi, contiene del testo
  • 0x2binary frame, questo frame, ed eventuali successivi, contiene dati in formato binario
  • 0x3 - x7 – riservati a frame che non siano di controllo, per essere sfruttati da estensioni di websocket
  • 0x8close frame, questo frame dovrebbe chiudere la connessione
  • 0x9ping frame
  • 0xApong frame
  • 0xB - 0xF – riservati a frame di controllo
Mask (bit 8)determina se un certo frame usi una maschera o no
Lunghezza del Payload (bits 9-15, o 16-31, o 16-79)questi sette bit indicano la lunghezza del contenuto: se il valore in questo set è 126, la lunghezza viene rappresentata dai seguenti 2Bytes (bit 16-31), se invece è 127, la rappresentazione viene estesa fino al bit 79 (4byte in più)
Masking Key (i seguenti 4 Byte)Rappresenta la maschera, quando il bit Mask è impostato a 1
Payload (tutti i dati successivi)finalmente i dati. È possibile trasferire il payload con più frame: conosciamo la lunghezza effettiva del messaggio grazie all’informazione sulla lunghezza che abbiamo codificato nell’header del frame e possiamo aggiungere dati finché non riceviamo un frame con il flag Fin. Tutti i frame consecutivi saranno contrassegnati dall’opcode 0x0 (continuation frame).

Il frame dei dati nella RFC6455 ci permette di capire quanto sia grande un messaggi, il tipo di codifica e l’eventuale maschera. Possiamo inviare messaggi di qualunque lunghezza, purché questa lunghezza sia rappresentabile con un numero base-64 (cioè 9.223.372.036.854.775.808 cifre).

Se vuoi aggiornamenti su Introduzione ai WebSocket inserisci la tua e-mail nel box qui sotto:
 
X
Se vuoi aggiornamenti su Introduzione ai WebSocket

inserisci la tua e-mail nel box qui sotto:

Ho letto e acconsento l'informativa sulla privacy

Acconsento al trattamento di cui al punto 3 dell'informativa sulla privacy