Qu’est-ce que les Websockets?

Au cours des dernières années, un nouveau type de communication a commencé à émerger sur le web et dans les apps mobiles, appelé websockets. Ce protocole était attendu depuis longtemps et a finalement été normalisé par l’IETF en 2011, ouvrant la voie à une utilisation généralisée.

Ce nouveau protocole ouvre une ligne de communication beaucoup plus rapide et efficace vers le client. Comme HTTP, les websockets fonctionnent au-dessus d’une connexion TCP, mais ils sont beaucoup plus rapides car nous n’avons pas besoin d’ouvrir une nouvelle connexion à chaque fois que nous voulons envoyer un message puisque la connexion est maintenue en vie aussi longtemps que le serveur ou le client le souhaite.

Mieux encore, puisque la connexion ne meurt jamais, nous disposons enfin d’une communication en duplex intégral, ce qui signifie que nous pouvons pousser des données vers le client au lieu de devoir attendre qu’il demande des données au serveur. Cela permet de communiquer des données dans les deux sens, ce qui est idéal pour des choses comme les applications de chat en temps réel, ou même les jeux.

Comment fonctionnent les websockets ?

À la base, un websocket est juste une connexion TCP qui permet une communication full-duplex, ce qui signifie que chaque côté de la connexion peut envoyer des données à l’autre, même en même temps.

Pour établir cette connexion, le protocole initie en fait la poignée de main comme une demande HTTP normale, mais il est ensuite  » mis à niveau  » à l’aide de l’en-tête HTTP de demande de mise à niveau, comme ceci :

Le serveur renvoie alors une réponse HTTP 101  » Switching Protocols « , accusant réception de la mise à niveau de la connexion. Une fois cette connexion établie, il passe à un protocole binaire bidirectionnel, à partir duquel les données de l’application peuvent être envoyées.

Tout ce que le protocole doit faire pour maintenir la connexion ouverte est d’envoyer quelques paquets ping/pong, ce qui indique à l’autre partie qu’elle est toujours là. Pour fermer la connexion, un simple paquet  » close connection  » est envoyé.

Quelques exemples de Websocket

Parmi les nombreuses bibliothèques websocket pour Node.js à notre disposition, j’ai choisi d’utiliser socket.io tout au long de cet article car elle semble être la plus populaire et est, à mon avis, la plus facile à utiliser. Bien que chaque bibliothèque ait sa propre API unique, elles ont également de nombreuses similitudes puisqu’elles sont toutes construites au-dessus du même protocole, donc j’espère que vous serez en mesure de traduire le code ci-dessous à n’importe quelle bibliothèque que vous voulez utiliser.

Pour le serveur HTTP, j’utiliserai Express, qui est le serveur Node le plus populaire là-bas. Gardez à l’esprit que vous pouvez aussi simplement utiliser le module http ordinaire si vous n’avez pas besoin de toutes les fonctionnalités d’Express. Bien que, puisque la plupart des applications utiliseront Express, c’est ce que nous utiliserons également.

Note : Tout au long de ces exemples, j’ai supprimé une grande partie du code passe-partout, donc une partie de ce code ne fonctionnera pas hors de la boîte. Dans la plupart des cas, vous pouvez vous référer au premier exemple pour obtenir le code boilerplate.

Établissement de la connexion

Pour qu’une connexion soit établie entre le client et le serveur, le serveur doit faire deux choses :

  1. S’accrocher au serveur HTTP pour gérer les connexions websocket
  2. Servir la socket.io.js bibliothèque du client comme une ressource statique

Dans le code ci-dessous, vous pouvez voir l’élément (1) être fait sur la 3e ligne. L’élément (2) est fait pour vous (par défaut) par la bibliothèque socket.io et est servi sur le chemin https://stackabuse.com/socket.io/socket.io.js. Par défaut, toutes les connexions et ressources websocket sont servies dans le chemin /socket.io.

Serveur

Le client doit également faire deux choses :

  1. Charger la bibliothèque depuis le serveur
  2. Appeler .connect() l’adresse du serveur et le chemin du websocket

Client

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

Si vous faites naviguer votre navigateur vers et que vous inspectez les requêtes HTTP en coulisse à l’aide des outils de développement de votre navigateur, vous devriez être en mesure de voir la poignée de main en cours d’exécution, y compris les demandes GET et la réponse HTTP 101 Switching Protocols qui en résulte.

Envoyer des données du serveur au client

Ok, passons maintenant aux parties les plus intéressantes. Dans cet exemple, nous allons vous montrer la façon la plus courante d’envoyer des données du serveur au client. Dans ce cas, nous allons envoyer un message à un canal, qui peut être souscrit et reçu par le client. Ainsi, par exemple, une application client pourrait écouter le canal ‘announcements’, qui contiendrait des notifications sur des événements à l’échelle du système, comme lorsqu’un utilisateur rejoint un salon de discussion.

Sur le serveur, cela se fait en attendant que la nouvelle connexion soit établie, puis en appelant la méthode socket.emit() pour envoyer un message à tous les clients connectés.

Serveur

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

Client

Envoi de données du client au serveur

Mais que ferions-nous lorsque nous voudrions envoyer des données dans l’autre sens, du client au serveur ? C’est très similaire au dernier exemple, en utilisant à la fois les méthodes socket.emit() et socket.on().

Serveur

Client

Comptage des utilisateurs connectés

C’est un exemple intéressant à apprendre car il montre quelques fonctionnalités supplémentaires de socket.io (comme l’événement disconnect), il est facile à mettre en œuvre et il est applicable à de nombreuses webapps. Nous allons utiliser les événements connection et disconnect pour compter le nombre d’utilisateurs actifs sur notre site, et nous mettrons à jour tous les utilisateurs avec le compte actuel.

Serveur

Client

Une façon beaucoup plus simple de suivre le nombre d’utilisateurs sur le serveur serait de simplement utiliser ceci:

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

Mais apparemment il y a quelques problèmes autour de cela, donc vous pourriez avoir à suivre le compte du client vous-même.

Rooms et espaces de noms

Il est fort probable qu’à mesure que votre application gagne en complexité, vous ayez besoin de plus de personnalisation avec vos websockets, comme envoyer des messages à un utilisateur ou un ensemble d’utilisateurs spécifiques. Ou peut-être voulez-vous une séparation stricte de la logique entre les différentes parties de votre application. C’est là que les rooms et les espaces de noms entrent en jeu.

Note : Ces fonctionnalités ne font pas partie du protocole websocket, mais sont ajoutées par-dessus par socket.io.

Par défaut, socket.io utilise l’espace de noms racine (/) pour envoyer et recevoir des données. Programmatiquement, vous pouvez accéder à cet espace de noms via io.sockets, bien que nombre de ses méthodes aient des raccourcis sur io. Ces deux appels sont donc équivalents :

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

Pour créer votre propre espace de noms, il vous suffit de faire ce qui suit :

De plus, le client doit se connecter à votre espace de noms de manière explicite :

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

Maintenant, toutes les données envoyées dans cet espace de nom seront distinctes de l’espace de nom par défaut /, quel que soit le canal utilisé.

Pour aller encore plus loin, au sein de chaque espace de nom, vous pouvez rejoindre et quitter des  » salles « . Ces salles fournissent une autre couche de séparation au-dessus des espaces de noms, et comme un client ne peut être ajouté à une salle que du côté du serveur, elles fournissent également une certaine sécurité supplémentaire. Ainsi, si vous voulez vous assurer que les utilisateurs ne fouinent pas sur certaines données, vous pouvez utiliser une salle pour les cacher.

Pour être ajouté à une salle, vous devez .join() le:

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

Puis de là, vous pouvez envoyer des messages à toutes les personnes appartenant à la salle donnée :

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

Et enfin, appelez .leave() pour arrêter de recevoir des messages d’événement d’une salle :

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

Conclusion

Ce n’est qu’une bibliothèque qui met en œuvre le protocole websockets, et il en existe beaucoup d’autres, toutes avec leurs propres caractéristiques et forces uniques. Je conseillerais d’en essayer d’autres (comme node-websockets) afin d’avoir une idée de ce qui existe.

En quelques lignes seulement, vous pouvez créer des applications assez puissantes, alors je suis curieux de voir ce que vous pouvez imaginer !

Catégories : Articles

0 commentaire

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *