Introduzione ai WebSocket: portare i socket sul Web

Il problema: connessioni client-server e server-client a bassa latenza

Il web è stato ampiamente costruito intorno al cosiddetto paradigma richiesta/risposta di HTTP. Un client carica una pagina web e poi non accade nulla finché l'utente non fa clic sulla pagina successiva. Intorno al 2005, AJAX ha iniziato a rendere il web più dinamico. Tuttavia, tutte le comunicazioni HTTP erano gestite dal client, che richiedeva l'interazione dell'utente o polling periodico per caricare nuovi dati dal server.

Tecnologie che consentono al server di inviare dati al client nel momento esatto in cui sa che sono disponibili nuovi dati da tempo. con nomi come "Push" o 'Comet'. Uno degli attacchi più comuni per creare l'illusione di una connessione avviata dal server è chiamato lungo polling. Con un polling lungo, il client apre una connessione HTTP al server che la mantiene aperta fino all'invio della risposta. Ogni volta che il server dispone effettivamente di nuovi dati, invia la risposta (altre tecniche includono richieste Flash, XHR multipart e i cosiddetti htmlfile). I sondaggi lunghi e le altre tecniche funzionano abbastanza bene. Puoi utilizzarle ogni giorno in applicazioni come la chat di Gmail.

Tuttavia, tutte queste soluzioni condividono un problema: portano l'overhead del protocollo HTTP, il che non li rende adatti alle applicazioni a bassa latenza. Pensa a giochi sparatutto in prima persona multiplayer nel browser o a qualsiasi altro gioco online con un componente in tempo reale.

Introduzione a WebSocket: introduzione dei socket sul web

La specifica WebSocket definisce un'API che stabilisce connessioni "socket" tra un browser web e un server. In parole semplici: esiste una connessione persistente tra il client e il server ed entrambe le parti possono iniziare a inviare dati in qualsiasi momento.

Per iniziare

Puoi aprire una connessione WebSocket semplicemente chiamando il costruttore WebSocket:

var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);

Osserva il ws:. Questo è il nuovo schema URL per le connessioni WebSocket. Esiste anche wss: per una connessione WebSocket sicura, allo stesso modo in cui https: viene utilizzato per le connessioni HTTP sicure.

L'associazione immediata di alcuni gestori di eventi alla connessione ti consente di sapere quando la connessione è stata aperta, se hai ricevuto i messaggi in arrivo o se si è verificato un errore.

Il secondo argomento accetta sottoprotocolli facoltativi. Può essere una stringa o un array di stringhe. Ogni stringa deve rappresentare un nome di sottoprotocollo e il server accetta solo uno dei sottoprotocolli passati nell'array. Il sottoprotocollo accettato può essere determinato accedendo alla proprietà protocol dell'oggetto WebSocket.

I nomi di sottoprotocolli devono essere uno dei nomi di sottoprotocolli registrati nel registro IANA. Attualmente esiste un solo nome di sottoprotocollo (soap) registrato a partire da febbraio 2012.

// When the connection is open, send some data to the server
connection.onopen = function () {
connection.send('Ping'); // Send the message 'Ping' to the server
};

// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};

// Log messages from the server
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};

Comunicare con il server

Non appena viene stabilita una connessione al server (quando viene attivato l'evento open), possiamo iniziare a inviare dati al server utilizzando il metodo send('your message') sull'oggetto connessione. Un tempo supportava solo le stringhe, ma nelle specifiche più recenti ora può inviare anche messaggi binari. Per inviare dati binari, puoi utilizzare l'oggetto Blob o ArrayBuffer.

// Sending String
connection.send('your message');

// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
binary[i] = img.data[i];
}
connection.send(binary.buffer);

// Sending file as Blob
var file = document.querySelector('input[type="file"]').files[0];
connection.send(file);

Allo stesso modo, il server potrebbe inviarci messaggi in qualsiasi momento. In questo caso si attiva il callback onmessage. Il callback riceve un oggetto evento e il messaggio effettivo è accessibile tramite la proprietà data.

WebSocket può anche ricevere messaggi binari nelle specifiche più recenti. I frame binari possono essere ricevuti nel formato Blob o ArrayBuffer. Per specificare il formato del programma binario ricevuto, imposta la proprietà binaria dell'oggetto WebSocket su "blob" o "arraybuffer". Il formato predefinito è "blob". Non devi allineare il parametro binarioType all'invio.

// Setting binaryType to accept received binary as either 'blob' or 'arraybuffer'
connection.binaryType = 'arraybuffer';
connection.onmessage = function(e) {
console.log(e.data.byteLength); // ArrayBuffer object if binary
};

Un'altra funzionalità appena aggiunta di WebSocket sono le estensioni. Utilizzando le estensioni, sarà possibile inviare frame compressi, multiplix e così via. Puoi trovare le estensioni accettate dal server esaminando la proprietà delle estensioni dell'oggetto WebSocket dopo l'evento aperto. Non sono ancora disponibili specifiche delle estensioni pubblicate ufficialmente a febbraio 2012.

// Determining accepted extensions
console.log(connection.extensions);

Comunicazione multiorigine

Essendo un protocollo moderno, la comunicazione multiorigine è integrata direttamente in WebSocket. Anche se dovresti comunque assicurarti di comunicare solo con client e server che ritieni affidabili, WebSocket consente la comunicazione tra le parti su qualsiasi dominio. Il server decide se rendere il servizio disponibile per tutti i client o solo per quelli che risiedono in un insieme di domini ben definiti.

Server proxy

Ogni nuova tecnologia comporta una serie di problemi nuovi. WebSocket è la compatibilità con i server proxy a mediare le connessioni HTTP nella maggior parte delle reti aziendali. Il protocollo WebSocket utilizza il sistema di upgrade HTTP (che normalmente viene utilizzato per HTTP/SSL) per "eseguire l'upgrade" di una connessione HTTP a una connessione WebSocket. Ad alcuni server proxy non piace e la connessione viene interrotta. Quindi, anche se un determinato client utilizza il protocollo WebSocket, potrebbe non essere possibile stabilire una connessione. Questo rende la sezione successiva ancora più importante :)

Usa subito WebSocket

WebSocket è ancora una tecnologia giovane e non è stata completamente implementata in tutti i browser. Tuttavia, puoi usare subito WebSocket con librerie che usano uno dei fallback menzionati sopra ogni volta che WebSocket non è disponibile. Una libreria molto diffusa in questo dominio è socket.io, che include un'implementazione del protocollo e un client con il server e include i fallback (a partire da febbraio 2012, socket.io non supporta ancora i messaggi binari). Esistono anche soluzioni commerciali come PusherApp che possono essere facilmente integrate in qualsiasi ambiente web fornendo un'API HTTP per inviare messaggi WebSocket ai client. A causa della richiesta HTTP aggiuntiva, ci sarà sempre un sovraccarico rispetto a WebSocket puro.

Lato server

L'utilizzo di WebSocket crea un modello di utilizzo completamente nuovo per le applicazioni lato server. Sebbene gli stack di server tradizionali come LAMP siano progettati in base al ciclo di richiesta/risposta HTTP, spesso non gestiscono bene un numero elevato di connessioni WebSocket aperte. Mantenere un numero elevato di connessioni aperte contemporaneamente richiede un'architettura che riceva un'elevata contemporaneità a costi inferiori per le prestazioni. Queste architetture sono solitamente progettate per il threading, o cosiddetti IO non bloccanti.

Implementazioni lato server

Versioni del protocollo

Il protocollo di rete (un handshake e il trasferimento di dati tra client e server) per WebSocket è ora RFC6455. Le versioni più recenti di Chrome e Chrome per Android sono completamente compatibili con RFC6455, inclusi i messaggi binari. Inoltre, Firefox sarà compatibile nella versione 11 e Internet Explorer nella versione 10. Puoi continuare a utilizzare le versioni precedenti del protocollo, ma questa operazione è sconsigliata perché è noto che sono vulnerabili. Se disponi di implementazioni server per versioni precedenti del protocollo WebSocket, ti consigliamo di eseguirne l'upgrade alla versione più recente.

casi d'uso

Utilizza WebSocket ogni volta che hai bisogno di una latenza davvero bassa, quasi in tempo reale, tra il client e il server. Tieni presente che questo potrebbe comportare la ripensamento del modo in cui crei le tue applicazioni lato server, concentrandoti su tecnologie come le code di eventi. Alcuni esempi di casi d'uso sono:

  • Giochi multiplayer online
  • Applicazioni di chat
  • Riquadro di aggiornamento sport in diretta
  • Aggiornamento in tempo reale dei social stream

Demo

Riferimenti