Le Web en temps réel avec Socket.io

Publié le Mis à jour le

Nous avons connu les pages statiques, puis les pages dynamiques, et depuis quelques années nous connaissons des pages qui, avec Ajax, autorisent des rechargements partiels. Aujourd’hui, tout va très vite sur internet, et il est de plus en plus apprécié d’avoir accès à certaines informations instantanément : emails, tweets, etc… Le protocole HTTP ne convient plus pour ces nouveaux besoins et le W3C l’a bien compris. Bien qu’il existe d’autres solutions permettant la communication en temps réel avec un serveur Web, le W3C a récemment introduit la notion de WebSockets. Cependant, celles-ci ne sont actuellement pas supportées par tous les navigateurs.

Petit tour des méthodes alternatives :

AJAX

La plupart des développeurs Web ont déjà utilisé AJAX, et l’émergence de librairies telles que jQuery a participé à son explosion sur le marché. Un grand nombre de sites Web actuels utilisent l’ajax, ce qui leur permet entre autres de récupérer en quasi-temps réel des informations provenant du serveur. Il suffit en effet d’interroger le serveur régulièrement, afin de vérifier s’il y a de nouvelles informations à afficher :

Mis à part le fait que ce n’est pas réellement du temps réel, cette solution pose un problème majeur. Les requêtes sont faites toutes les secondes, qu’il y ait de nouvelles informations à afficher ou non. En cas de forte affluence sur le site, cette méthode risque donc de surcharger le serveur pour peu de choses.

L’AJAX Long Polling

Le long polling est une variation du polling expliqué ci-dessus, même si le principe est un peu différent. La même requête est faite au serveur, mais si celui-ci ne possède pas de données à envoyer, la connexion est laissée ouverte. Elle sera par la suite fermée soit par l’arrivée d’une réponse, soit après un certain laps de temps (aussi appelé «timeout»). Le client relance alors une requête dès la fermeture de la connexion précédente, ce qui permet au serveur d’envoyer des données à n’importe quel moment.

Il existe une autre possibilité, le streaming. Dans ce cas, une seule connexion persistante est créée entre le client et le serveur. Il est alors possible pour le serveur d’envoyer des événements, et pour le client de les traiter, sans qu’aucun des deux ne ferme la connexion.

Dans les deux cas, il existe en permanence une connexion au serveur par client, ce qui peut conduire à la surcharge du serveur : le problème de cette méthode vient donc du fait que de (trop ?) nombreuses connexions peuvent être ouvertes simultanément.

L’AJAX multipart streaming

Cette méthode n’est que peu utilisée car elle n’est disponible que sur les navigateurs basés sur le moteur de rendu Gecko (Firefox, …).
Elle consiste à utiliser l’objet XMLHttpRequest (qui permet de faire de l’AJAX), en rajoutant le paramètre multipart = true, ce qui aura pour effet d’utiliser le content type multipart/x-mixed-replace, et permettra de streamer les données.

La forever iframe

Cette technique consiste à cacher une iframe dans la page, dont le header comportera les mentions Transfer-encoding: chunked, et Connection: keep-alive.
Il suffit ensuite d’écrire au fur et à mesure des tags dans cette iframe pour executer du code Javascript côté client.

Cette technique fonctionne avec à peu près tous les navigateurs, même si certains d’entre eux afficheront indéfiniment une barre de chargement.

Websocket

Les Websockets sont un mécanisme pour les applications Web, qui nécessite une communication bi-directionnelle avec le serveur, et qui ne repose pas sur plusieurs connexions HTTP (ie. l’utilisation de XMLHttpRequest, d’iframe, ou de long polling). La spécification des Websockets, encore au stade de «Draft»en (brouillon), détaille le fonctionnement théorique de cette méthode.

Les Websockets sont disponibles dans les dernières versions des navigateurs les plus connus tels que Firefox, Google Chrome, Opera, et Safari. Néanmoins, celles-ci sont désactivées par défaut dans les tous derniers builds de Firefox et d’Opéra, en raison de problèmes de sécurité identifiés récemment.

Beaucoup de méthodes, laquelle choisir ?

La librairie socket.ioen pour nodejsen vous sort le moral des sockets et va faire le choix pour vous. Nous avons découvert cette librairie lors d’une des «coding evening» de Clever Age, ce qui nous a permis de coder plus rapidement et donc de manger plus de pizzas.

Pour rappel, nodejsen est un “outil basé sur le moteur javascript V8 qui permet le développement d’applications serveur à l’aide de Javascript.” (copyright @Palleas)
Ajoutons simplement qu’il utilise la notion de programmation événementielle, où l’on définit le comportement que doit avoir le programme face aux différents événements possibles.

Pour l’installation, rien de très compliqué :


$ git clone https://github.com/ry/node.git
$ ./configure && make && make install

Installons ensuite npm, un package manager pour node :


$ curl http://npmjs.org/install.sh | sh

Enfin, installons socket.io :


$ npm install socket.io

Après inclusion de la librairie dans le code du serveur et dans le code du client, elle déterminera automatiquement la meilleure méthode disponible lors de problématiques de temps réel. socket.io supporte l’utilisation des Websockets, de l’AJAX long polling, de l’AJAX multipart streaming, et de la forever iframe, …

Pour le serveur, il suffit de créer un «httpserver» de nodejs, d’attacher ce serveur à une instance de socket.io, et de définir les callbacks des évènements. Côté client, il faut définir des callbacks sur les différents événements disponibles une fois la connexion au serveur effectuée.

Très facilement, et même avec de l’huile piquante pour pizza plein les doigts, il est alors possible de créer un petit serveur qui enverra tous les tweets parlant de Justin Bieber à tous les clients présents sur une page :

Client :

Et voilà ! Ouvrez la page contenant le client, et il ne reste plus qu’à constater le sidérant nombre de tweets parlant de Justin Bieber qui défilent à l’écran[Rappelons que [3% des serveurs de Twitter sont utilisés pour les tweets (et RT) de Justin Bieber…]] !


  • Développement

  • JavaScript

  • Performance Web (WebPerf)