Présentation de WebSockets : sockets sur le Web

Le problème: à faible latence des connexions client-serveur et serveur-client

Le Web s'est largement construit autour du paradigme de requête/réponse du protocole HTTP. Un client charge une page Web, puis rien ne se passe avant que l'utilisateur ne clique sur la page suivante. Vers 2005, AJAX a commencé à rendre le Web plus dynamique. Pourtant, toutes les communications HTTP étaient pilotées par le client, ce qui nécessitait une interaction de l'utilisateur ou des interrogations périodiques pour charger de nouvelles données à partir du serveur.

Les technologies qui permettent au serveur d'envoyer des données au client au moment précis où il sait que de nouvelles données sont disponibles existent depuis un certain temps. Ils sont appelés "Pousser" ou "Comet". L’un des trucs les plus courants pour créer l’illusion d’une connexion initiée par le serveur est appelé « long interrogation ». En cas d'interrogation longue, le client ouvre une connexion HTTP au serveur qui la maintient ouvert jusqu'à l'envoi de la réponse. Chaque fois que le serveur dispose de nouvelles données, il envoie la réponse (d'autres techniques impliquent des requêtes Flash, XHR multipart ou htmlfiles). Les sondages longs et les autres techniques fonctionnent très bien. Vous les utilisez tous les jours dans des applications telles que le chat Gmail.

Cependant, toutes ces solutions de contournement partagent un problème: elles entraînent la surcharge du protocole HTTP, ce qui ne les rend pas adaptées aux applications à faible latence. Il peut s'agir de jeux de tir multijoueurs à la première personne dans un navigateur ou de tout autre jeu en ligne avec un composant en temps réel.

Présentation de WebSocket: utilisation des sockets sur le Web

La spécification WebSocket définit une API qui établit des connexions de type "socket" entre un navigateur Web et un serveur. En clair: la connexion entre le client et le serveur est permanente, et les deux parties peuvent commencer à envoyer des données à tout moment.

Premiers pas

Pour ouvrir une connexion WebSocket, il vous suffit d'appeler le constructeur WebSocket:

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

Notez le ws:. Il s'agit du nouveau schéma d'URL pour les connexions WebSocket. Il existe également wss: pour une connexion WebSocket sécurisée, de la même manière que https: est utilisé pour les connexions HTTP sécurisées.

Le fait d'associer immédiatement certains gestionnaires d'événements à la connexion vous permet de savoir quand la connexion est ouverte, quand il a reçu des messages entrants ou quand il y a une erreur.

Le deuxième argument accepte des sous-protocoles facultatifs. Il peut s'agir d'une chaîne ou d'un tableau de chaînes. Chaque chaîne doit représenter un nom de sous-protocole, et le serveur n'accepte qu'un seul des sous-protocoles transmis dans le tableau. Le sous-protocole accepté peut être déterminé en accédant à la propriété protocol de l'objet WebSocket.

Les noms de sous-protocoles doivent correspondre à l'un des noms de sous-protocoles enregistrés dans le registre de l'IANA. À l'heure actuelle, en février 2012, il n'existe qu'un seul nom de sous-protocole (sonon) enregistré.

// 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);
};

Communication avec le serveur

Dès que nous sommes connectés au serveur (lorsque l'événement open est déclenché), nous pouvons commencer à envoyer des données au serveur à l'aide de la méthode send('your message') sur l'objet de connexion. Auparavant, elle n'acceptait que les chaînes, mais dans la dernière spécification, il peut désormais également envoyer des messages binaires. Pour envoyer des données binaires, vous pouvez utiliser l'objet Blob ou 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);

De même, le serveur peut nous envoyer des messages à tout moment. Chaque fois que cela se produit, le rappel onmessage se déclenche. Le rappel reçoit un objet événement, et le message est accessible via la propriété data.

WebSocket peut également recevoir des messages binaires selon la spécification la plus récente. Les trames binaires peuvent être reçues au format Blob ou ArrayBuffer. Pour spécifier le format du binaire reçu, définissez la propriété binaryType de l'objet WebSocket sur "blob" ou "arraybuffer". Le format par défaut est "blob". Il n'est pas nécessaire d'aligner le paramètre "BinaryType" lors de l'envoi.

// 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
};

Une autre fonctionnalité récemment ajoutée à WebSocket est les extensions. À l'aide d'extensions, il sera possible d'envoyer des trames compressées, multiplexées, etc. Pour trouver les extensions acceptées par le serveur, examinez la propriété des extensions de l'objet WebSocket après l'événement ouvert. Aucune spécification d'extension n'a été publiée officiellement en février 2012.

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

Communication multi-origine

En tant que protocole moderne, la communication multi-origine est intégrée directement à WebSocket. Même si vous devez toujours vous assurer de ne communiquer qu'avec les clients et les serveurs de confiance, WebSocket permet la communication entre les parties sur n'importe quel domaine. Le serveur décide de mettre son service à la disposition de tous les clients ou seulement de ceux résidant sur un ensemble de domaines bien définis.

Serveurs proxy

Chaque nouvelle technologie s'accompagne d'un nouvel ensemble de problèmes. Dans le cas de WebSocket, il s'agit de la compatibilité avec les serveurs proxy qui arbitrent les connexions HTTP dans la plupart des réseaux d'entreprise. Le protocole WebSocket utilise le système de mise à niveau HTTP (généralement utilisé pour HTTP/SSL) pour "mettre à niveau" une connexion HTTP en connexion WebSocket. Certains serveurs proxy n'aiment pas cette méthode et interrompront la connexion. Ainsi, même si un client donné utilise le protocole WebSocket, il n'est pas toujours possible d'établir une connexion. Cela rend la section suivante encore plus importante :)

Utiliser WebSockets dès aujourd'hui

WebSocket est une technologie encore récente qui n'est pas complètement implémentée dans tous les navigateurs. Toutefois, vous pouvez actuellement utiliser WebSocket avec des bibliothèques qui utilisent l'une des solutions de remplacement mentionnées ci-dessus chaque fois que WebSocket n'est pas disponible. La bibliothèque socket.io est devenue très populaire dans ce domaine. Elle est fournie avec un client et une mise en œuvre du protocole, et inclut des solutions de remplacement (socket.io n'est pas encore compatible avec la messagerie binaire depuis février 2012). Il existe également des solutions commerciales telles que PusherApp, qui peuvent être facilement intégrées à n'importe quel environnement Web en fournissant une API HTTP pour envoyer des messages WebSocket aux clients. En raison de la demande HTTP supplémentaire, il y aura toujours une surcharge supplémentaire par rapport au WebSocket pur.

Côté serveur

L'utilisation de WebSocket crée un tout nouveau modèle d'utilisation pour les applications côté serveur. Bien que les piles de serveurs traditionnelles telles que LAMP soient conçues autour du cycle de requête/réponse HTTP, elles ne fonctionnent souvent pas bien avec un grand nombre de connexions WebSocket ouvertes. Garder un grand nombre de connexions ouvertes en même temps nécessite une architecture qui bénéficie d'une simultanéité élevée pour un coût de performance faible. Ces architectures sont généralement conçues autour des threads ou des E/S non bloquantes.

Implémentations côté serveur

Versions du protocole

Le protocole de communication de WebSocket (un handshake et le transfert de données entre le client et le serveur) est désormais le document RFC6455. Les dernières versions de Chrome et de Chrome pour Android sont entièrement compatibles avec la norme RFC6455, y compris la messagerie binaire. Notez également que Firefox est compatible avec les versions 11 et 10 d'Internet Explorer. Vous pouvez toujours utiliser d'anciennes versions du protocole, mais cela n'est pas recommandé, car elles sont connues pour être vulnérables. Si vous disposez de serveurs pour d'anciennes versions du protocole WebSocket, nous vous recommandons de passer à la dernière version.

Cas d'utilisation

Utilisez WebSocket chaque fois que vous avez besoin d'une connexion quasiment en temps réel et à faible latence entre le client et le serveur. N'oubliez pas que vous devrez peut-être repenser la façon dont vous créez vos applications côté serveur, en vous concentrant sur les technologies telles que les files d'attente d'événements. Voici quelques exemples de cas d'utilisation:

  • Jeux multijoueurs en ligne
  • Applications de chat
  • Témoin de sport en direct
  • Mettre à jour les flux de réseaux sociaux en temps réel

Démonstrations

Références