diff options
author | julieng <julien.gattelier@gmail.com> | 2021-10-02 17:20:24 +0200 |
---|---|---|
committer | SphinxKnight <SphinxKnight@users.noreply.github.com> | 2021-10-02 17:30:20 +0200 |
commit | 1407c8fdef01ecd0ffb8a8bd46e7113f119b9fde (patch) | |
tree | 30a56efd3eff3a01bd1611e1840fdbbfacf544a4 /files/fr/web/api/websockets_api | |
parent | c05efa8d7ae464235cf83d7c0956e42dc6974103 (diff) | |
download | translated-content-1407c8fdef01ecd0ffb8a8bd46e7113f119b9fde.tar.gz translated-content-1407c8fdef01ecd0ffb8a8bd46e7113f119b9fde.tar.bz2 translated-content-1407c8fdef01ecd0ffb8a8bd46e7113f119b9fde.zip |
convert content to md
Diffstat (limited to 'files/fr/web/api/websockets_api')
4 files changed, 382 insertions, 454 deletions
diff --git a/files/fr/web/api/websockets_api/index.md b/files/fr/web/api/websockets_api/index.md index 3a1f82be97..e82c924000 100644 --- a/files/fr/web/api/websockets_api/index.md +++ b/files/fr/web/api/websockets_api/index.md @@ -15,100 +15,86 @@ tags: - interactive translation_of: Web/API/WebSockets_API --- -<p>{{DefaultAPISidebar("Websockets API")}}</p> - -<p>L'<strong>API WebSocket</strong> est une technologie évoluée qui permet d'ouvrir un canal de communication bidirectionnelle entre un navigateur (côté client) et un serveur. Avec cette API vous pouvez envoyer des messages à un serveur et recevoir ses réponses de manière événementielle sans avoir à aller consulter le serveur pour obtenir une réponse.</p> - -<div class="note"> -<p><strong>Note :</strong> Bien que les connexions WebSocket soient fonctionnellement similaires aux sockets standard de type Unix, elles ne sont pas liées.</p> -</div> - -<h2 id="Interfaces">Interfaces </h2> - -<dl> - <dt><code><a href="/fr/docs/WebSockets/Writing_WebSocket_client_applications">WebSocket</a></code></dt> - <dd>Interface principale pour se connecter à un serveur WebSocket. Il permet d'envoyer et de recevoir des données sur la connexion.</dd> - <dt><code><a href="/fr/docs/Web/API/CloseEvent">CloseEvent</a></code></dt> - <dd>Evénement envoyé par l'objet WebSocket lors de la fermeture de la connexion.</dd> - <dt><code><a href="/fr/docs/Web/API/MessageEvent">MessageEvent</a></code></dt> - <dd>Evénement envoyé par l'objet WebSocket lorsqu'un message est reçu par le serveur.</dd> -</dl> - -<h2 id="Guides">Guides</h2> - -<ul> - <li><a href="/fr/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications">Ecrire des applications client WebSocket </a></li> - <li><a href="/fr/docs/Web/API/WebSockets_API/Writing_WebSocket_servers">Écriture de serveurs WebSocket </a></li> - <li><a href="/fr/docs/Web/API/WebSockets_API/Writing_WebSocket_server">Écrire un serveur WebSocket en C#</a></li> - <li><a href="/fr/docs/Web/API/WebSockets_API/Writing_a_WebSocket_server_in_Java">Écrire un serveur WebSocket en Java </a></li> -</ul> - -<h2 id="Outils">Outils</h2> - -<ul> - <li> <a href="https://humblenet.github.io/">HumbleNet</a> :Bibliothèque de réseau multiplateforme qui fonctionne dans un navigateur. Il s'agit bibliothèque écrite en C qui enveloppe WebSockets et WebRTC. Elle gomme toutes les différences qui existent entre les navigateurs et les logiciels, ce qui facilite la création d'une fonctionnalité de réseau multi-joueurs pour les jeux, par exemple, et autres applications.</li> - <li><a href="https://github.com/uWebSockets/uWebSockets">µWebSockets</a>: Déclinaison plus légère et plus performante de WebSocket et écrite en <a href="https://isocpp.org/">C++11</a> et en <a href="https://nodejs.org/fr/">Node.js</a>.</li> - <li><a href="https://github.com/ClusterWS/ClusterWS">ClusteWS</a>: Framework léger, rapide et puissant qui permet de construire des application en <a href="https://nodejs.org/fr/">Node.js</a>.</li> - <li><a href="http://socket.io">Socket.IO</a>: API WebSocket puissante et multiplateformes en <a href="http://nodejs.org">Node.js</a>.</li> - <li><a href="https://socketcluster.io/#!/">SocketCluster</a>: Framework open source en temps réel en <a href="http://nodejs.org">Node.js</a>. Il prend en charge à la fois la communication directe client-serveur et la communication de groupe via les pub/sub canaux. Il est conçu pour s'adapter facilement à n'importe quel nombre de processus/hôtes et est idéal pour construire de chat de discution.</li> - <li><a href="http://nodejs.org">Node.js</a>.</li> - <li><a href="https://www.totaljs.com/">Total.js</a>: FrameWork pour web application en <a href="http://nodejs.org">Node.js</a>.</li> - <li><a href="https://www.npmjs.com/package/faye-websocket">Faye</a>: Combine WebSocket(bidirectionnelle) et EventSource(unidirectionnelle) , côté serveur et côté client en <a href="http://nodejs.org">Node.js</a>.</li> - <li><a href="http://signalr.net/">SignalR</a>: SignalR est une nouvelle bibliothèque pour les développeurs <a href="https://dotnet.microsoft.com/apps/aspnet">ASP.NET</a>. Elle simplifie l'ajout des WebSockets dans les applications. SignalR utilise les canaux de WebSockets lorsqu'elles sont disponibles, dans le cas contraire elle utilise d'autres technos, sans modifier votre application.</li> - <li><a href="https://caddyserver.com/docs/websocket">Caddy</a>: Serveur web capable de créer des WebSockets serveur/proxy(stdin/stdout, echo, cat, ...).</li> - <li><a href="https://github.com/websockets/ws">ws</a>: La plus populaire des WebSockets pour client & serveur en <a href="http://nodejs.org">Node.js</a>.</li> - <li><a href="https://github.com/bigstepinc/jsonrpc-bidirectional">jsonrpc-bidirectional</a>: Asynchronous RPC which, on a single connection, may have functions exported on the server and, and the same time, on the client (client may call server, server may also call client).</li> - <li><a href="https://github.com/ninenines/cowboy">cowboy</a>: Cowboy est un petit serveur HTTP rapide et moderne pour Erlang/OTP basé sur WebSocket.</li> -</ul> - -<h2 id="Ressources_liées">Ressources liées</h2> - -<ul> - <li><a href="/fr/docs/AJAX">AJAX</a></li> - <li><a href="/fr/docs/Web/JavaScript">JavaScript</a></li> -</ul> - -<h2 id="Spécifications">Spécifications</h2> +{{DefaultAPISidebar("Websockets API")}} -<table class="standard-table"> - <thead> - <tr> - <th scope="col">Spécification</th> - <th scope="col">Statut</th> - <th scope="col">Commentaires</th> - </tr> - </thead> - <tbody> - <tr> - <td>{{SpecName("HTML WHATWG", "web-sockets.html", "WebSocket API")}}</td> - <td>{{Spec2("HTML WHATWG")}}</td> - <td></td> - </tr> - <tr> - <td><a href="https://www.w3.org/TR/websockets/">WebSockets</a></td> - <td> - <p>Candidat au statut de Recommendation</p> - </td> - <td></td> - </tr> - <tr> - <td>{{RFC(6455, "The WebSocket Protocol")}}</td> - <td>IETF RFC</td> - <td></td> - </tr> - </tbody> -</table> +L'**API WebSocket** est une technologie évoluée qui permet d'ouvrir un canal de communication bidirectionnelle entre un navigateur (côté client) et un serveur. Avec cette API vous pouvez envoyer des messages à un serveur et recevoir ses réponses de manière événementielle sans avoir à aller consulter le serveur pour obtenir une réponse. + +> **Note :** Bien que les connexions WebSocket soient fonctionnellement similaires aux sockets standard de type Unix, elles ne sont pas liées. + +## Interfaces + +- [`WebSocket`](/fr/docs/WebSockets/Writing_WebSocket_client_applications) + - : Interface principale pour se connecter à un serveur WebSocket. Il permet d'envoyer et de recevoir des données sur la connexion. +- [`CloseEvent`](/fr/docs/Web/API/CloseEvent) + - : Evénement envoyé par l'objet WebSocket lors de la fermeture de la connexion. +- [`MessageEvent`](/fr/docs/Web/API/MessageEvent) + - : Evénement envoyé par l'objet WebSocket lorsqu'un message est reçu par le serveur. + +## Guides + +- [Ecrire des applications client WebSocket](/fr/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications) +- [Écriture de serveurs WebSocket](/fr/docs/Web/API/WebSockets_API/Writing_WebSocket_servers) +- [Écrire un serveur WebSocket en C#](/fr/docs/Web/API/WebSockets_API/Writing_WebSocket_server) +- [Écrire un serveur WebSocket en Java](/fr/docs/Web/API/WebSockets_API/Writing_a_WebSocket_server_in_Java) -<h2 id="Compatibilité_des_navigateurs">Compatibilité des navigateurs</h2> +## Outils +- [HumbleNet](https://humblenet.github.io/) :Bibliothèque de réseau multiplateforme qui fonctionne dans un navigateur. Il s'agit bibliothèque écrite en C qui enveloppe WebSockets et WebRTC. Elle gomme toutes les différences qui existent entre les navigateurs et les logiciels, ce qui facilite la création d'une fonctionnalité de réseau multi-joueurs pour les jeux, par exemple, et autres applications. +- [µWebSockets](https://github.com/uWebSockets/uWebSockets): Déclinaison plus légère et plus performante de WebSocket et écrite en [C++11](https://isocpp.org/) et en [Node.js](https://nodejs.org/fr/). +- [ClusteWS](https://github.com/ClusterWS/ClusterWS): Framework léger, rapide et puissant qui permet de construire des application en [Node.js](https://nodejs.org/fr/). +- [Socket.IO](http://socket.io): API WebSocket puissante et multiplateformes en [Node.js](http://nodejs.org). +- [SocketCluster](https://socketcluster.io/#!/): Framework open source en temps réel en [Node.js](http://nodejs.org). Il prend en charge à la fois la communication directe client-serveur et la communication de groupe via les pub/sub canaux. Il est conçu pour s'adapter facilement à n'importe quel nombre de processus/hôtes et est idéal pour construire de chat de discution. +- [Node.js](http://nodejs.org). +- [Total.js](https://www.totaljs.com/): FrameWork pour web application en [Node.js](http://nodejs.org). +- [Faye](https://www.npmjs.com/package/faye-websocket): Combine WebSocket(bidirectionnelle) et EventSource(unidirectionnelle) , côté serveur et côté client en [Node.js](http://nodejs.org). +- [SignalR](http://signalr.net/): SignalR est une nouvelle bibliothèque pour les développeurs [ASP.NET](https://dotnet.microsoft.com/apps/aspnet). Elle simplifie l'ajout des WebSockets dans les applications. SignalR utilise les canaux de WebSockets lorsqu'elles sont disponibles, dans le cas contraire elle utilise d'autres technos, sans modifier votre application. +- [Caddy](https://caddyserver.com/docs/websocket): Serveur web capable de créer des WebSockets serveur/proxy(stdin/stdout, echo, cat, ...). +- [ws](https://github.com/websockets/ws): La plus populaire des WebSockets pour client & serveur en [Node.js](http://nodejs.org). +- [jsonrpc-bidirectional](https://github.com/bigstepinc/jsonrpc-bidirectional): Asynchronous RPC which, on a single connection, may have functions exported on the server and, and the same time, on the client (client may call server, server may also call client). +- [cowboy](https://github.com/ninenines/cowboy): Cowboy est un petit serveur HTTP rapide et moderne pour Erlang/OTP basé sur WebSocket. + +## Ressources liées + +- [AJAX](/fr/docs/AJAX) +- [JavaScript](/fr/docs/Web/JavaScript) + +## Spécifications + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Spécification</th> + <th scope="col">Statut</th> + <th scope="col">Commentaires</th> + </tr> + </thead> + <tbody> + <tr> + <td> + {{SpecName("HTML WHATWG", "web-sockets.html", "WebSocket API")}} + </td> + <td>{{Spec2("HTML WHATWG")}}</td> + <td></td> + </tr> + <tr> + <td><a href="https://www.w3.org/TR/websockets/">WebSockets</a></td> + <td><p>Candidat au statut de Recommendation</p></td> + <td></td> + </tr> + <tr> + <td>{{RFC(6455, "The WebSocket Protocol")}}</td> + <td>IETF RFC</td> + <td></td> + </tr> + </tbody> +</table> +## Compatibilité des navigateurs -<p>{{Compat("api.WebSocket")}}</p> +{{Compat("api.WebSocket")}} -<h2 id="Voir_aussi">Voir aussi</h2> +## Voir aussi -<ul> - <li><a href="http://tools.ietf.org/html/rfc6455">RFC 6455 - Le protocole WebSocket</a></li> - <li><a href="http://www.w3.org/TR/websockets/">Les spécifications de l'API WebSocket</a></li> - <li><a href="/fr/docs/Web/API/Server-sent_events">Server-Sent Events</a></li> -</ul> +- [RFC 6455 - Le protocole WebSocket](http://tools.ietf.org/html/rfc6455) +- [Les spécifications de l'API WebSocket](http://www.w3.org/TR/websockets/) +- [Server-Sent Events](/fr/docs/Web/API/Server-sent_events) diff --git a/files/fr/web/api/websockets_api/writing_a_websocket_server_in_java/index.md b/files/fr/web/api/websockets_api/writing_a_websocket_server_in_java/index.md index bf8ac63d44..76489af66b 100644 --- a/files/fr/web/api/websockets_api/writing_a_websocket_server_in_java/index.md +++ b/files/fr/web/api/websockets_api/writing_a_websocket_server_in_java/index.md @@ -3,29 +3,32 @@ title: Écrire un serveur WebSocket en Java slug: Web/API/WebSockets_API/Writing_a_WebSocket_server_in_Java translation_of: Web/API/WebSockets_API/Writing_a_WebSocket_server_in_Java --- -<h2 id="Introduction">Introduction</h2> +## Introduction -<p>Cet exemple montre comment cérer une serveur d'API WebSocket API utilisant Java d'Oracle.</p> +Cet exemple montre comment cérer une serveur d'API WebSocket API utilisant Java d'Oracle. -<p>Bien que d'autres languages exécutés côté serveur peuvent être utilisés pour créer un serveur de WebSocket, cet exemple utilise Java d'Oracle pour simplifier le code en exemple.</p> +Bien que d'autres languages exécutés côté serveur peuvent être utilisés pour créer un serveur de WebSocket, cet exemple utilise Java d'Oracle pour simplifier le code en exemple. -<p>Ce seveur respecte la <a href="http://tools.ietf.org/html/rfc6455">RFC 6455</a>, dont il prend uniquement en charge les connexions depuis Chrome 16, Firefox 11, IE 10 et au delà.</p> +Ce seveur respecte la [RFC 6455](http://tools.ietf.org/html/rfc6455), dont il prend uniquement en charge les connexions depuis Chrome 16, Firefox 11, IE 10 et au delà. -<h2 id="Premiers_pas">Premiers pas</h2> +## Premiers pas -<p>WebSockets communique via une connexion <a href="http://en.wikipedia.org/wiki/Transmission_Control_Protocol">TCP (Transmission Control Protocol)</a>. La classe Java <a href="http://docs.oracle.com/javase/8/docs/api/java/net/ServerSocket.html">ServerSocket</a> est située dans le paquet <em>java.net</em>.</p> +WebSockets communique via une connexion [TCP (Transmission Control Protocol)](http://en.wikipedia.org/wiki/Transmission_Control_Protocol). La classe Java [ServerSocket](http://docs.oracle.com/javase/8/docs/api/java/net/ServerSocket.html) est située dans le paquet _java.net_. -<h3 id="ServerSocket">ServerSocket</h3> +### ServerSocket -<p>Constructeur :</p> +Constructeur : -<pre class="brush: java"><code>ServerSocket(int port)</code></pre> +```java +ServerSocket(int port) +``` -<p>Lors de l'instanciation de la classe ServerSocket, celle-ci est liée au numéro de port renseigné par le paramètre <em>port</em>.</p> +Lors de l'instanciation de la classe ServerSocket, celle-ci est liée au numéro de port renseigné par le paramètre _port_. -<p>Voici comment implémenter ce que nous venons d'apprendre :</p> +Voici comment implémenter ce que nous venons d'apprendre : -<pre class="brush: java">import java.net.ServerSocket; +```java +import java.net.ServerSocket; import java.net.Socket; public class Server{ @@ -38,40 +41,44 @@ public class Server{ System.out.println("Un client s’est connecté."); } -}</pre> +} +``` -<h3 id="Socket">Socket</h3> +### Socket -<p>Méthodes :</p> +Méthodes : -<ul> - <li><code>java.net.</code><a href="http://docs.oracle.com/javase/8/docs/api/java/net/Socket.html">Socket</a><code> <a href="http://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#getInputStream--">getInputStream</a>()</code><br> - Renvoie un flux d’entrée pour ce socket.</li> - <li><code>java.net.</code><a href="http://docs.oracle.com/javase/8/docs/api/java/net/Socket.html">Socket</a><code> <a href="http://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#getOutputStream--">getOutputStream</a>()</code><br> - Renvoie un flux sortant pour ce socket.</li> -</ul> +- `java.net.`[Socket](http://docs.oracle.com/javase/8/docs/api/java/net/Socket.html)` getInputStream()` + Renvoie un flux d’entrée pour ce socket. +- `java.net.`[Socket](http://docs.oracle.com/javase/8/docs/api/java/net/Socket.html)` getOutputStream()` + Renvoie un flux sortant pour ce socket. -<h3 id="OutputStream">OutputStream</h3> +### OutputStream -<p>Méthode :</p> +Méthode : -<pre class="brush: java">write<code>(byte[] b, int off, int len)</code></pre> +```java +write(byte[] b, int off, int len) +``` -<p>En débutant à partir de la position <em>off</em>, écrit <em><code>len</code></em> octets du tableau d'octets fourni.</p> +En débutant à partir de la position _off_, écrit _`len`_ octets du tableau d'octets fourni. -<h3 id="InputStream">InputStream</h3> +### InputStream -<p>Méthodes :</p> +Méthodes : -<pre class="brush: java">read<code>(byte[] b, int off, int len)</code></pre> +```java +read(byte[] b, int off, int len) +``` -<p>Reads up to <em>len</em> bytes of data from the input stream into an array of bytes.<em> </em></p> +Reads up to _len_ bytes of data from the input stream into an array of bytes.\*\* -<p>Lit jusqu'à <em>len</em> octets de données depuis source d'entrée dans un tableau d'octets.</p> +Lit jusqu'à _len_ octets de données depuis source d'entrée dans un tableau d'octets. -<p>Développons notre exemple.</p> +Développons notre exemple. -<pre class="brush: java">Socket client = server.accept(); +```java +Socket client = server.accept(); System.out.println("Un client s’est connecté."); @@ -79,13 +86,15 @@ InputStream in = client.getInputStream(); OutputStream out = client.getOutputStream(); -new Scanner(in, "UTF-8").useDelimiter("\\r\\n\\r\\n").next();</pre> +new Scanner(in, "UTF-8").useDelimiter("\\r\\n\\r\\n").next(); +``` -<h2 id="Établissement_d‘une_liaison_(handshaking)">Établissement d‘une liaison (handshaking)</h2> +## Établissement d‘une liaison (handshaking) -<p>Quand un client se connecte à un serveur, il envoit une requête GET pour passer à une connexion WebSocket à partir d'une simple connexion HTTP. Ceci est appelé l’établissement d’une liaison.</p> +Quand un client se connecte à un serveur, il envoit une requête GET pour passer à une connexion WebSocket à partir d'une simple connexion HTTP. Ceci est appelé l’établissement d’une liaison. -<pre class="brush: java">import java.util.Scanner; +```java +import java.util.Scanner; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -98,20 +107,20 @@ if (get.find()) { } else { -}</pre> +} +``` -<p>Créer une réponse est plus facile que de comprendre pourquoi vous devez le faire comme ça.</p> +Créer une réponse est plus facile que de comprendre pourquoi vous devez le faire comme ça. -<p>Vous devez,</p> +Vous devez, -<ol> - <li>obtenir la valeur de la requête d’entête <em>Sec-WebSocket-Key</em> sans aucun espacement;</li> - <li>la lier avec « 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 »;</li> - <li>en calculer les codes SHA-1 et Base64;</li> - <li>renvoyer le résultat comme valeur de l'entête de réponse <em>Sec-WebSocket-Accept</em> qui sera une partie d’une réponse HTTP.</li> -</ol> +1. obtenir la valeur de la requête d’entête _Sec-WebSocket-Key_ sans aucun espacement; +2. la lier avec « 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 »; +3. en calculer les codes SHA-1 et Base64; +4. renvoyer le résultat comme valeur de l'entête de réponse _Sec-WebSocket-Accept_ qui sera une partie d’une réponse HTTP. -<pre class="brush: java">if (get.find()) { +```java +if (get.find()) { Matcher match = Pattern.compile("Sec-WebSocket-Key: (.*)").matcher(data); match.find(); byte[] response = ("HTTP/1.1 101 Switching Protocols\r\n" @@ -129,89 +138,70 @@ if (get.find()) { out.write(response, 0, response.length); } -</pre> +``` -<h2 id="Décoder_les_messages">Décoder les messages</h2> +## Décoder les messages -<p>Après l’établissement réussie d’une liaison, le client peut transmettre des messages au serveur, ils seront désormais encodés.</p> +Après l’établissement réussie d’une liaison, le client peut transmettre des messages au serveur, ils seront désormais encodés. -<p>Si nous envoyons « abcdef », nous obtenons :</p> +Si nous envoyons « abcdef », nous obtenons : <table> - <tbody> - <tr> - <td>129</td> - <td>134</td> - <td>167</td> - <td>225</td> - <td>225</td> - <td>210</td> - <td>198</td> - <td>131</td> - <td>130</td> - <td>182</td> - <td>194</td> - <td>135</td> - </tr> - </tbody> + <tbody> + <tr> + <td>129</td> + <td>134</td> + <td>167</td> + <td>225</td> + <td>225</td> + <td>210</td> + <td>198</td> + <td>131</td> + <td>130</td> + <td>182</td> + <td>194</td> + <td>135</td> + </tr> + </tbody> </table> -<p>- 129:</p> +\- 129: -<table> - <thead> - <tr> - <th scope="col">FIN (est-ce la totalité du message ?)</th> - <th scope="col">RSV1</th> - <th scope="col">RSV2</th> - <th scope="col">RSV3</th> - <th scope="col">Opcode</th> - </tr> - </thead> - <tbody> - <tr> - <td>1</td> - <td>0</td> - <td>0</td> - <td>0</td> - <td>0x1=0001</td> - </tr> - </tbody> -</table> +| FIN (est-ce la totalité du message ?) | RSV1 | RSV2 | RSV3 | Opcode | +| ------------------------------------- | ---- | ---- | ---- | -------- | +| 1 | 0 | 0 | 0 | 0x1=0001 | -<p>FIN : votre message peut être transmis en plusieurs morceaux, mais restons simple pour l’instant.<br> - Opcode <em>0x1</em> signifie que ceci est un texte. <a href="http://tools.ietf.org/html/rfc6455#section-5.2">Liste exhaustive des Opcodes</a></p> +FIN : votre message peut être transmis en plusieurs morceaux, mais restons simple pour l’instant. +Opcode _0x1_ signifie que ceci est un texte. [Liste exhaustive des Opcodes](http://tools.ietf.org/html/rfc6455#section-5.2) -<p>- 134:</p> +\- 134: -<p>If the second byte minus 128 is between 0 and 125, this is the length of the message. If it is 126, the following 2 bytes (16-bit unsigned integer), if 127, the following 8 bytes (64-bit unsigned integer, the most significant bit MUST be 0) are the length.</p> +If the second byte minus 128 is between 0 and 125, this is the length of the message. If it is 126, the following 2 bytes (16-bit unsigned integer), if 127, the following 8 bytes (64-bit unsigned integer, the most significant bit MUST be 0) are the length. -<p>Si le second octet moins 128 est entre 0 et 125, alors il s’agit de la longueur du message. Si c’est 126, les deux octets suivants (entier non signé de 16-bits), si c’est 127, les huit octets suivants (entier non signé de 64-bis, dont le poid ford doit être 0) sont la longueur.</p> +Si le second octet moins 128 est entre 0 et 125, alors il s’agit de la longueur du message. Si c’est 126, les deux octets suivants (entier non signé de 16-bits), si c’est 127, les huit octets suivants (entier non signé de 64-bis, dont le poid ford doit être 0) sont la longueur. -<div class="note"> -<p><strong>Note :</strong> Je peux prendre 128 car le premier bit est toujours 1.</p> -</div> +> **Note :** Je peux prendre 128 car le premier bit est toujours 1. -<p>- 167, 225, 225 et 210 sont les octets de la clef à décoder. Cela change en permanence.</p> +\- 167, 225, 225 et 210 sont les octets de la clef à décoder. Cela change en permanence. -<p>- Les octets encodés restants constituent le message.</p> +\- Les octets encodés restants constituent le message. -<h3 id="Algorithme_de_décodage">Algorithme de décodage</h3> +### Algorithme de décodage -<p>octet décodé = octet encodé XOR (position de l’octet ET LOGIQUE 0x3)th octet de la clef</p> +octet décodé = octet encodé XOR (position de l’octet ET LOGIQUE 0x3)th octet de la clef -<p>Exemple en Java :</p> +Exemple en Java : -<pre class="brush: java">byte[] decoded = new byte[6]; +```java +byte[] decoded = new byte[6]; byte[] encoded = new byte[] {198, 131, 130, 182, 194, 135}; byte[] key = byte[4] {167, 225, 225, 210}; -for (int i = 0; i < encoded.length; i++) { - decoded[i] = (byte)(encoded[i] ^ key[i & 0x3]); -}</pre> +for (int i = 0; i < encoded.length; i++) { + decoded[i] = (byte)(encoded[i] ^ key[i & 0x3]); +} +``` -<h2 id="Voir_aussi">Voir aussi</h2> +## Voir aussi -<ul> - <li><a href="/fr/docs/WebSockets/Writing_WebSocket_servers">Écriture de serveurs WebSocket</a></li> -</ul> +- [Écriture de serveurs WebSocket](/fr/docs/WebSockets/Writing_WebSocket_servers) diff --git a/files/fr/web/api/websockets_api/writing_websocket_client_applications/index.md b/files/fr/web/api/websockets_api/writing_websocket_client_applications/index.md index d2cf5fccbf..e646af9f9b 100644 --- a/files/fr/web/api/websockets_api/writing_websocket_client_applications/index.md +++ b/files/fr/web/api/websockets_api/writing_websocket_client_applications/index.md @@ -3,94 +3,88 @@ title: Ecrire des applications client WebSocket slug: Web/API/WebSockets_API/Writing_WebSocket_client_applications translation_of: Web/API/WebSockets_API/Writing_WebSocket_client_applications --- -<p>Les WebSockets représentent une technologie, basée sur le protocole web socket, qui permet d'établir une session de communication bilatérale entre un navigateur web et un serveur. Un navigateur web est un exemple typique de client websocket typique mais le protocole n'est dépendant d'aucune plateforme.</p> +Les WebSockets représentent une technologie, basée sur le protocole web socket, qui permet d'établir une session de communication bilatérale entre un navigateur web et un serveur. Un navigateur web est un exemple typique de client websocket typique mais le protocole n'est dépendant d'aucune plateforme. -<div class="note"> - <p><strong>Note :</strong> Un exemple d'utilisation des WebSockets à travers un système de chat sera mis à disposition sous forme de code dès que nos infrastructures seront en mesure de supporter les WebSockets.</p> -</div> +> **Note :** Un exemple d'utilisation des WebSockets à travers un système de chat sera mis à disposition sous forme de code dès que nos infrastructures seront en mesure de supporter les WebSockets. -<p>{{AvailableInWorkers}}</p> +{{AvailableInWorkers}} -<h2 id="Création_d'un_objet_WebSocket">Création d'un objet WebSocket</h2> +## Création d'un objet WebSocket -<p>Pour utiliser le protocole WebSocket, il faut créer un objet <a href="/en/WebSockets/WebSockets_reference/WebSocket"><code>WebSocket</code></a> ; celui-ci essaiera automatiquement d'ouvrir une connexion avec le server.</p> +Pour utiliser le protocole WebSocket, il faut créer un objet [`WebSocket`](/en/WebSockets/WebSockets_reference/WebSocket) ; celui-ci essaiera automatiquement d'ouvrir une connexion avec le server. -<p>Le constructeur WebSocket accepte un paramètre obligatoire et un paramètre optionnel :</p> +Le constructeur WebSocket accepte un paramètre obligatoire et un paramètre optionnel : -<pre>WebSocket WebSocket( - in DOMString url, - in optional DOMString protocols -); + WebSocket WebSocket( + in DOMString url, + in optional DOMString protocols + ); -WebSocket WebSocket( - in DOMString url, - in optional DOMString[] protocols -); -</pre> + WebSocket WebSocket( + in DOMString url, + in optional DOMString[] protocols + ); -<dl> - <dt><code>url</code></dt> - <dd>L'URL à laquelle le client se connecte, et le serveur répond.</dd> - <dt><code>protocols</code> {{ optional_inline() }}</dt> - <dd>Soit une chaîne décrivant un protocole unique, soit une liste de chaînes décrivant chacune un protocole. Ces chaînes permettent d'indiquer des sous-protocoles, de façon à ce qu'un serveur puisse implémenter plusieurs sous-protocoles WebSocket (par example, on pourrait vouloir qu'un serveur soit capable de traiter différents types d'interactions en fonction du protocole spécifié). Si aucun protocole n'est spécifié, l'argument prend la valeur d'une chaîne vide.</dd> -</dl> +- `url` + - : L'URL à laquelle le client se connecte, et le serveur répond. +- `protocols` {{ optional_inline() }} + - : Soit une chaîne décrivant un protocole unique, soit une liste de chaînes décrivant chacune un protocole. Ces chaînes permettent d'indiquer des sous-protocoles, de façon à ce qu'un serveur puisse implémenter plusieurs sous-protocoles WebSocket (par example, on pourrait vouloir qu'un serveur soit capable de traiter différents types d'interactions en fonction du protocole spécifié). Si aucun protocole n'est spécifié, l'argument prend la valeur d'une chaîne vide. -<p>Le constructeur peut renvoyer des exceptions:</p> +Le constructeur peut renvoyer des exceptions: -<dl> - <dt><code>SECURITY_ERR</code></dt> - <dd>Le port sur lequel on essaie d'établir la connexion est bloqué.</dd> -</dl> +- `SECURITY_ERR` + - : Le port sur lequel on essaie d'établir la connexion est bloqué. -<dl> -</dl> +<!----> -<h3 id="Erreurs_de_connexion">Erreurs de connexion</h3> +### Erreurs de connexion -<p>Si une erreur se produit lors de la tentative de connexion, un évènement nommé "error" est d'abord renvoyé à l'objet <a href="/en/WebSockets/WebSockets_reference/WebSocket"><code>WebSocket</code></a> (invoquant ainsi son gestionnaire d'évènement <code>onerror</code>) suivi d'un évènement <a href="/en/WebSockets/WebSockets_reference/CloseEvent"><code>CloseEvent</code></a> (qui invoque alors son gestionnaire d'évènement <code>onclose</code>) indiquant la raison de la clôture.</p> +Si une erreur se produit lors de la tentative de connexion, un évènement nommé "error" est d'abord renvoyé à l'objet [`WebSocket`](/en/WebSockets/WebSockets_reference/WebSocket) (invoquant ainsi son gestionnaire d'évènement `onerror`) suivi d'un évènement [`CloseEvent`](/en/WebSockets/WebSockets_reference/CloseEvent) (qui invoque alors son gestionnaire d'évènement `onclose`) indiquant la raison de la clôture. -<p>A partir de Firefox 11, un message d'erreur descriptif est envoyé à la console de la plateforme Mozilla, et un code de fermeture tel que défini dans la <a href="http://tools.ietf.org/html/rfc6455#section-7.4">RFC 6455, Section 7.4</a> est envoyé à travers l'évènement <a href="/en/WebSockets/WebSockets_reference/CloseEvent"><code>CloseEvent</code></a>.</p> +A partir de Firefox 11, un message d'erreur descriptif est envoyé à la console de la plateforme Mozilla, et un code de fermeture tel que défini dans la [RFC 6455, Section 7.4](http://tools.ietf.org/html/rfc6455#section-7.4) est envoyé à travers l'évènement [`CloseEvent`](/en/WebSockets/WebSockets_reference/CloseEvent). -<h3 id="Exemples">Exemples</h3> +### Exemples -<p>Cet exemple simple crée un nouvel objet WebSocket, qui se connecte au serveur à l'adresse <code>ws://www.example.com/socketserver</code>. Un protocole spécifique "protocolOne" est indiqué dans cette exemple, bien qu'il ne soit pas obligatoire.</p> +Cet exemple simple crée un nouvel objet WebSocket, qui se connecte au serveur à l'adresse `ws://www.example.com/socketserver`. Un protocole spécifique "protocolOne" est indiqué dans cette exemple, bien qu'il ne soit pas obligatoire. -<pre class="brush: js">var exampleSocket = new WebSocket("ws://www.example.com/socketserver", "protocolOne"); -</pre> +```js +var exampleSocket = new WebSocket("ws://www.example.com/socketserver", "protocolOne"); +``` -<p>Lorsque la connexion est établie, la propriété <code>readyState</code> de l'objet <code>exampleSocket </code>prend la valeur <code>CONNECTING</code>. Sa valeur devient <code>OPEN</code> une fois que la connexion est prête à transférer des données.</p> +Lorsque la connexion est établie, la propriété `readyState` de l'objet `exampleSocket `prend la valeur `CONNECTING`. Sa valeur devient `OPEN` une fois que la connexion est prête à transférer des données. -<p>Pour ouvrir une connexion flexible quant aux protocoles supportés, on spécifie une liste de protocoles:</p> +Pour ouvrir une connexion flexible quant aux protocoles supportés, on spécifie une liste de protocoles: -<pre class="brush: js">var exampleSocket = new WebSocket("ws://www.example.com/socketserver", ["protocolOne", "protocolTwo"]); -</pre> +```js +var exampleSocket = new WebSocket("ws://www.example.com/socketserver", ["protocolOne", "protocolTwo"]); +``` -<p>Une fois la connexion établie (c'est-à-dire quand <code>readyState</code> a la valeur <code>OPEN</code>), la propriété <code>protocol</code> indique quel protocole le server a sélectionné.</p> +Une fois la connexion établie (c'est-à-dire quand `readyState` a la valeur `OPEN`), la propriété `protocol` indique quel protocole le server a sélectionné. -<p>Dans les exemples ci-dessus on a remplacé <code>http</code> par <code>ws</code>, et de la même façon on peut remplacer <code>https</code> par <code>wss</code> . L'établissement d'une connexion WebSocket repose sur le méchanisme HTTP Upgrade, donc la requête pour l'upgrade de protocole est implicite lorsqu'on s'adresse au server HTTP avec <code>ws://www.example.com</code> ou <code>wss://www.example.com</code>.</p> +Dans les exemples ci-dessus on a remplacé `http` par `ws`, et de la même façon on peut remplacer `https` par `wss` . L'établissement d'une connexion WebSocket repose sur le méchanisme HTTP Upgrade, donc la requête pour l'upgrade de protocole est implicite lorsqu'on s'adresse au server HTTP avec `ws://www.example.com` ou `wss://www.example.com`. -<h2 id="Envoi_de_données_vers_le_serveur">Envoi de données vers le serveur</h2> +## Envoi de données vers le serveur -<p>Une fois la connexion ouverte on peut commencer à tranférer des données vers le serveur en appelant la méthode <a href="/en/WebSockets/WebSockets_reference/WebSocket#send()"><code>send()</code></a> de l'objet <code>WebSocket</code> pour chaque message que l'on veut envoyer :</p> +Une fois la connexion ouverte on peut commencer à tranférer des données vers le serveur en appelant la méthode [`send()`](</en/WebSockets/WebSockets_reference/WebSocket#send()>) de l'objet `WebSocket` pour chaque message que l'on veut envoyer : -<p>Les données peuvent être envoyées sous forme de chaîne {{ domxref("Blob") }} ou de <a href="/en/JavaScript_typed_arrays/ArrayBuffer"><code>ArrayBuffer</code></a>.</p> +Les données peuvent être envoyées sous forme de chaîne {{ domxref("Blob") }} ou de [`ArrayBuffer`](/en/JavaScript_typed_arrays/ArrayBuffer). -<div class="note"> - <p><strong>Note :</strong> Avant la version 11, Firefox supportait l'envoi de données uniquement sous forme de chaîne.</p> -</div> +> **Note :** Avant la version 11, Firefox supportait l'envoi de données uniquement sous forme de chaîne. -<p>Comme l'établissement d'une connexion est asynchrone, et peut potentiellemet échouer, appeler la méthode <code>send()</code> juste après la création d'un objet WebSocket peut ne pas fonctionner. Il est plus sûr de définir un gestionnaire d'évènement <code>onopen</code>, et de n'essayer d'envoyer des données que lorsqu'il est appelé.</p> +Comme l'établissement d'une connexion est asynchrone, et peut potentiellemet échouer, appeler la méthode `send()` juste après la création d'un objet WebSocket peut ne pas fonctionner. Il est plus sûr de définir un gestionnaire d'évènement `onopen`, et de n'essayer d'envoyer des données que lorsqu'il est appelé. -<pre class="brush: js">exampleSocket.onopen = function (event) { +```js +exampleSocket.onopen = function (event) { exampleSocket.send("Voici un texte que le serveur attend de recevoir dès que possible !"); }; -</pre> +``` -<h3 id="Utilisation_de_JSON_pour_transmettre_des_objets">Utilisation de JSON pour transmettre des objets</h3> +### Utilisation de JSON pour transmettre des objets -<p>Il peut être utile d'utiliser <a href="/en/JSON">JSON</a> pour envoyer des données complexes au serveur. Par exemple, un programme de chat peut interagir avec un serveur en utilisant un protocole qui implémente l'échange de paquets contenant des données encapsulées en JSON:</p> +Il peut être utile d'utiliser [JSON](/en/JSON) pour envoyer des données complexes au serveur. Par exemple, un programme de chat peut interagir avec un serveur en utilisant un protocole qui implémente l'échange de paquets contenant des données encapsulées en JSON: -<pre class="brush: js">// Envoi d'un texte à tous les utilisateurs à travers le serveur +```js +// Envoi d'un texte à tous les utilisateurs à travers le serveur function sendText() { // Création d'un objet msg qui contient les données // dont le serveur a besoin pour traiter le message @@ -109,30 +103,30 @@ function sendText() { // que l'utilisateur va saisir document.getElementById("text").value = ""; } -</pre> +``` -<h2 id="Réception_de_données_du_serveur">Réception de données du serveur</h2> +## Réception de données du serveur -<p>WebSockets est une API orientée évènement; lorsqu'elle reçoit un message, un évènement "message" est envoyé au gestionnaire d'évènement <code>onmessage</code>. Pour écouter les données reçues, on peut écrire quelque chose comme:</p> +WebSockets est une API orientée évènement; lorsqu'elle reçoit un message, un évènement "message" est envoyé au gestionnaire d'évènement `onmessage`. Pour écouter les données reçues, on peut écrire quelque chose comme: -<pre class="brush: js">exampleSocket.onmessage = function (event) { +```js +exampleSocket.onmessage = function (event) { console.log(event.data); } -</pre> +``` -<h3 id="Réception_et_interprétation_d'objets_JSON">Réception et interprétation d'objets JSON</h3> +### Réception et interprétation d'objets JSON -<p>Considérons l'application de chat évoquée dans {{ anch("Utilisation de JSON pour transmettre des objets") }}. Le client peut recevoir différents types de paquets de données, tels que:</p> +Considérons l'application de chat évoquée dans {{ anch("Utilisation de JSON pour transmettre des objets") }}. Le client peut recevoir différents types de paquets de données, tels que: -<ul> - <li>établissement d'une liaison (handshaking)</li> - <li>message texte</li> - <li>mise à jour de la liste d'utilisateurs</li> -</ul> +- établissement d'une liaison (handshaking) +- message texte +- mise à jour de la liste d'utilisateurs -<p>Le code qui interprète ces messages entrants pourrait être:</p> +Le code qui interprète ces messages entrants pourrait être: -<pre class="brush: js">exampleSocket.onmessage = function(event) { +```js +exampleSocket.onmessage = function(event) { var f = document.getElementById("chatbox").contentDocument; var text = ""; var msg = JSON.parse(event.data); @@ -145,18 +139,18 @@ function sendText() { setUsername(); break; case "username": - text = "<b>User <em>" + msg.name + "</em> signed in at " + timeStr + "</b><br>"; + text = "<b>User <em>" + msg.name + "</em> signed in at " + timeStr + "</b><br>"; break; case "message": - text = "(" + timeStr + ") <b>" + msg.name + "</b>: " + msg.text + "<br>"; + text = "(" + timeStr + ") <b>" + msg.name + "</b>: " + msg.text + "<br>"; break; case "rejectusername": - text = "<b>Your username has been set to <em>" + msg.name + "</em> because the name you chose is in use.</b><br>" + text = "<b>Your username has been set to <em>" + msg.name + "</em> because the name you chose is in use.</b><br>" break; case "userlist": var ul = ""; - for (i=0; i < msg.users.length; i++) { - ul += msg.users[i] + "<br>"; + for (i=0; i < msg.users.length; i++) { + ul += msg.users[i] + "<br>"; } document.getElementById("userlistbox").innerHTML = ul; break; @@ -167,25 +161,26 @@ function sendText() { document.getElementById("chatbox").contentWindow.scrollByPages(1); } }; -</pre> +``` -<p>Ici nous utilisons <a href="/en/JavaScript/Reference/Global_Objects/JSON/parse"><code>JSON.parse()</code></a> pour convertir l'objet JSON en l'objet original, avant de l'examiner et le traiter.</p> +Ici nous utilisons [`JSON.parse()`](/en/JavaScript/Reference/Global_Objects/JSON/parse) pour convertir l'objet JSON en l'objet original, avant de l'examiner et le traiter. -<h3 id="Encodage_du_texte">Encodage du texte</h3> +### Encodage du texte -<p>Le texte reçu à travers une connexion WebSocket est encodé au format UTF-8.</p> +Le texte reçu à travers une connexion WebSocket est encodé au format UTF-8. -<p>Avant Gecko 9.0 {{ geckoRelease("9.0") }}, certains charactères spéciaux dans une chaîne UTF-8 provoquaient l'interruption de la connexion. Maintenant Gecko accepte ces caractères.</p> +Avant Gecko 9.0 {{ geckoRelease("9.0") }}, certains charactères spéciaux dans une chaîne UTF-8 provoquaient l'interruption de la connexion. Maintenant Gecko accepte ces caractères. -<h2 id="Fermeture_de_la_connexion">Fermeture de la connexion</h2> +## Fermeture de la connexion -<p>Quand on n'a plus besoin de la connexion WebSocket, on appelle la méthode <a href="/en/WebSockets/WebSockets_reference/WebSocket#close()"><code>close()</code></a> de l'objet WebSocket:</p> +Quand on n'a plus besoin de la connexion WebSocket, on appelle la méthode [`close()`](</en/WebSockets/WebSockets_reference/WebSocket#close()>) de l'objet WebSocket: -<pre class="brush: js">exampleSocket.close(); -</pre> +```js +exampleSocket.close(); +``` -<p>Il peut être utile de vérifier la valeur de l'attribut <code>bufferedAmount</code> avant de fermer la connexion, pour s'assurer qu'il ne reste pas des données qui n'ont pas été transmises.</p> +Il peut être utile de vérifier la valeur de l'attribut `bufferedAmount` avant de fermer la connexion, pour s'assurer qu'il ne reste pas des données qui n'ont pas été transmises. -<h2 id="Considérations_de_sécurité">Considérations de sécurité</h2> +## Considérations de sécurité -<p>Il est déconseillé d'utiliser les WebSockets dans un environnement mixte, c'est-à-dire qu'il ne faut pas établir de connexion Websocket non sécurisée depuis une page chargée en HTTPS, et inversement. Certains navigateurs l'interdisent explicitement, comme Firefox à partir de la version 8.</p> +Il est déconseillé d'utiliser les WebSockets dans un environnement mixte, c'est-à-dire qu'il ne faut pas établir de connexion Websocket non sécurisée depuis une page chargée en HTTPS, et inversement. Certains navigateurs l'interdisent explicitement, comme Firefox à partir de la version 8. diff --git a/files/fr/web/api/websockets_api/writing_websocket_servers/index.md b/files/fr/web/api/websockets_api/writing_websocket_servers/index.md index 5cc97ce8b0..cc30b5fdca 100644 --- a/files/fr/web/api/websockets_api/writing_websocket_servers/index.md +++ b/files/fr/web/api/websockets_api/writing_websocket_servers/index.md @@ -3,248 +3,205 @@ title: Écriture de serveurs WebSocket slug: Web/API/WebSockets_API/Writing_WebSocket_servers translation_of: Web/API/WebSockets_API/Writing_WebSocket_servers --- -<p>Un serveur WebSocket est une application TCP qui écoute sur n'importe quel port d'un serveur et suit un protocole spécifique, c'est aussi simple que cela. La création de son propre serveur TCP est quelque chose qui a tendance à effrayer alors qu'il n'est pas forcément très complexe de créer un serveur WebScoket sur la plateforme de votre choix.</p> +Un serveur WebSocket est une application TCP qui écoute sur n'importe quel port d'un serveur et suit un protocole spécifique, c'est aussi simple que cela. La création de son propre serveur TCP est quelque chose qui a tendance à effrayer alors qu'il n'est pas forcément très complexe de créer un serveur WebScoket sur la plateforme de votre choix. -<p>Un serveur WebSocket peut être écrit dans n'importe quel language de programmation qui supporte les "<a href="https://fr.wikipedia.org/wiki/Berkeley_sockets">Berkeley sockets</a>", par exemple C(++), python ou même PHP et JavaScript (avec nodejs). Ceci n'est pas un tutoriel destiné à un language particulier mais un guide aidant à l'écriture de votre propre serveur.</p> +Un serveur WebSocket peut être écrit dans n'importe quel language de programmation qui supporte les "[Berkeley sockets](https://fr.wikipedia.org/wiki/Berkeley_sockets)", par exemple C(++), python ou même PHP et JavaScript (avec nodejs). Ceci n'est pas un tutoriel destiné à un language particulier mais un guide aidant à l'écriture de votre propre serveur. -<p>Avant de débuter, vous <strong>devez</strong> connaître précisément le fonctionnement du protocole HTTP et disposer d'une certaine expérience sur celui-ci. Des connaissances sur les sockets TCP dans votre langage de développement est également précieux. Ce guide ne présente ainsi que le <em>minimum</em> des connaissances requises et non un guide ultime.</p> +Avant de débuter, vous **devez** connaître précisément le fonctionnement du protocole HTTP et disposer d'une certaine expérience sur celui-ci. Des connaissances sur les sockets TCP dans votre langage de développement est également précieux. Ce guide ne présente ainsi que le _minimum_ des connaissances requises et non un guide ultime. -<div class="note"> -<p><strong>Note :</strong> Lire la dernière spécification officielle sur les WebSockets <a href="http://datatracker.ietf.org/doc/rfc6455/?include_text=1">RFC 6455</a>. Les sections 1 et 4-7 sont particulièrement intéressantes pour ce qui nous occupe. La section 10 évoque la sécurité et doit être connue et mise en oeuvre avant d'exposer votre serveur au-delà du réseau local / lors de la mise en production.</p> -</div> +> **Note :** Lire la dernière spécification officielle sur les WebSockets [RFC 6455](http://datatracker.ietf.org/doc/rfc6455/?include_text=1). Les sections 1 et 4-7 sont particulièrement intéressantes pour ce qui nous occupe. La section 10 évoque la sécurité et doit être connue et mise en oeuvre avant d'exposer votre serveur au-delà du réseau local / lors de la mise en production. -<p>Un serveur WebSocket est compris ici en "bas niveau" (<em>c'est-à-dire plus proche du langage machine que du langage humain</em>. Les WebSockets sont souvent séparés et spécialisés vis-à-vis de leurs homologues serveurs (pour des questions de montées en charge ou d'autres raisons), donc vous devez souvent utiliser un <a href="https://fr.wikipedia.org/wiki/Proxy_inverse">proxy inverse</a> (<em>c'est-à-dire de l'extérieur vers l'intérieur du réseau local, comme pour un serveur HTTP classique</em>) pour détecter les "poignées de mains" spécifiques au WebSocket, qui précédent l'échange et permettent d'aiguiller les clients vers le bon logiciel. Dans ce cas, vous ne devez pas ajouter à votre serveur des <em>cookies</em> et d'autres méthodes d'authentification. </p> +Un serveur WebSocket est compris ici en "bas niveau" (_c'est-à-dire plus proche du langage machine que du langage humain_. Les WebSockets sont souvent séparés et spécialisés vis-à-vis de leurs homologues serveurs (pour des questions de montées en charge ou d'autres raisons), donc vous devez souvent utiliser un [proxy inverse](https://fr.wikipedia.org/wiki/Proxy_inverse) (_c'est-à-dire de l'extérieur vers l'intérieur du réseau local, comme pour un serveur HTTP classique_) pour détecter les "poignées de mains" spécifiques au WebSocket, qui précédent l'échange et permettent d'aiguiller les clients vers le bon logiciel. Dans ce cas, vous ne devez pas ajouter à votre serveur des *cookies* et d'autres méthodes d'authentification. -<h2 id="La_poignée_de_mains_du_WebSocket">La "poignée de mains" du WebSocket</h2> +## La "poignée de mains" du WebSocket -<p>En tout premier lieu, le serveur doit écouter les connexions sockets entrantes utilisant le protocole TCP standard. Suivant votre plateforme, celui-ci peut déjà le faire pour vous. Pour l'exemple qui suit, nous prenons pour acquis que votre serveur écoute le domaine <em>exemple.com</em> sur le port 8000 et votre serveur socket répond aux requêtes de type GET sur le chemin <em>/chat</em>. </p> +En tout premier lieu, le serveur doit écouter les connexions sockets entrantes utilisant le protocole TCP standard. Suivant votre plateforme, celui-ci peut déjà le faire pour vous. Pour l'exemple qui suit, nous prenons pour acquis que votre serveur écoute le domaine _exemple.com_ sur le port 8000 et votre serveur socket répond aux requêtes de type GET sur le chemin _/chat_. -<div class="warning"> -<p><strong>Attention :</strong> Si le serveur peut écouter n'importe quel port, mais que vous décidez de ne pas utiliser un port standard (80 ou 443 pour SSL), cela peut créer en avant des problèmes avec les parefeux et/ou les proxys. De plus, gardez en mémoire que certains navigateur Web (notablement Firefox 8+), n'autorisent pas les connexions WebSocket non-SSL sur une page SSL. </p> -</div> +> **Attention :** Si le serveur peut écouter n'importe quel port, mais que vous décidez de ne pas utiliser un port standard (80 ou 443 pour SSL), cela peut créer en avant des problèmes avec les parefeux et/ou les proxys. De plus, gardez en mémoire que certains navigateur Web (notablement Firefox 8+), n'autorisent pas les connexions WebSocket non-SSL sur une page SSL. -<p>La <em>poignée de mains</em> est la partie "Web" dans les WebSockets : c'est le pont entre le protocole HTTP et le WebSocket. Durant cette poignée, les détails (les paramètres) de la connexion sont négociés et l'une des parties peut interromptre la transaction avant la fin si l'un des termes ne lui est pas autorisé / ne lui est pas possible. Le serveur doit donc être attentif à comprendre parfaitement les demandes et attentes du client, sans quoi des procédures de sécurité seront déclenchées. </p> +La *poignée de mains* est la partie "Web" dans les WebSockets : c'est le pont entre le protocole HTTP et le WebSocket. Durant cette poignée, les détails (les paramètres) de la connexion sont négociés et l'une des parties peut interromptre la transaction avant la fin si l'un des termes ne lui est pas autorisé / ne lui est pas possible. Le serveur doit donc être attentif à comprendre parfaitement les demandes et attentes du client, sans quoi des procédures de sécurité seront déclenchées. -<h3 id="La_requête_de_poignée_de_mains_côté_client">La requête de <em>poignée de mains</em> côté client </h3> +### La requête de _poignée de mains_ côté client -<p>Même si vous construisez votre serveur au profit des WebSockets, votre client doit tout de même démarrer un processus dit de <em>poignée de main</em>. Vous devez donc savoir comment interprêter cette requête. En premier, le <strong>client </strong>enverra tout d'abord une requête HTTP correctement formée. La requête <strong>doit </strong>être à la version 1.1 ou supérieure et la méthode <strong>doit </strong>être de type GET : </p> +Même si vous construisez votre serveur au profit des WebSockets, votre client doit tout de même démarrer un processus dit de _poignée de main_. Vous devez donc savoir comment interprêter cette requête. En premier, le **client** enverra tout d'abord une requête HTTP correctement formée. La requête **doit** être à la version 1.1 ou supérieure et la méthode **doit** être de type GET : -<pre>GET /chat HTTP/1.1 -Host: exemple.com:8000 -<strong>Upgrade: websocket</strong> -<strong>Connection: Upgrade</strong> -Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== -Sec-WebSocket-Version: 13 + GET /chat HTTP/1.1 + Host: exemple.com:8000 + Upgrade: websocket + Connection: Upgrade + Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== + Sec-WebSocket-Version: 13 -</pre> +Le client peut solliciter des extensions de protocoles ou des sous-protocoles à cet instant ; voir [Miscellaneous](#Miscellaneous) pour les détails. En outre, des en-têtes communs tel que _User-Agent_, _Referer_, *Cookie* ou des en-têtes d'authentification peuvent être envoyés par la même requête : leur usage est laissé libre car ils ne se rapportent pas directement au WebSocket et au processus de poignée de main. A ce titre il semble préférable de les ignorer : d'ailleurs dans de nombreuses configurations communes, un proxy inverse les aura finalement déjà traitées. -<p>Le client peut solliciter des extensions de protocoles ou des sous-protocoles à cet instant ; voir <a href="#Miscellaneous">Miscellaneous</a> pour les détails. En outre, des en-têtes communs tel que <em>User-Agent</em>, <em>Referer</em>, <em>Cookie</em> ou des en-têtes d'authentification peuvent être envoyés par la même requête : leur usage est laissé libre car ils ne se rapportent pas directement au WebSocket et au processus de poignée de main. A ce titre il semble préférable de les ignorer : d'ailleurs dans de nombreuses configurations communes, un proxy inverse les aura finalement déjà traitées. </p> +Si un des entêtes n'est pas compris ou sa valeur n'est pas correcte, le serveur devrait envoyer une réponse "[400 Bad Request](/en-US/docs/HTTP/Response_codes#400)" (_erreur 400 : la requête est incorrecte_) et clore immédiatement la connexion. Il peut par ailleurs indiquer la raison pour laquelle la poignée de mains a échoué dans le corps de réponse HTTP, mais le message peut ne jamais être affiché par le navigateur (_en somme, tout dépend du comportement du client_). Si le serveur ne comprend pas la version de WebSockets présentée, il doit envoyer dans la réponse un entête _Sec-WebSocket-Version_ correspondant à la ou les version-s supportée-s. Ici le guide explique la version 13, la plus récente à l'heure de l'écriture du tutoriel (_voir le tutoriel en version anglaise pour la date exacte ; il s'agit là d'une traduction_). Maintenant, nous allons passer à l'entête attendu : *Sec-WebSocket-Key*. -<p>Si un des entêtes n'est pas compris ou sa valeur n'est pas correcte, le serveur devrait envoyer une réponse "<a href="/en-US/docs/HTTP/Response_codes#400">400 Bad Request</a>" (<em>erreur 400 : la requête est incorrecte</em>) et clore immédiatement la connexion. Il peut par ailleurs indiquer la raison pour laquelle la poignée de mains a échoué dans le corps de réponse HTTP, mais le message peut ne jamais être affiché par le navigateur (<em>en somme, tout dépend du comportement du client</em>). Si le serveur ne comprend pas la version de WebSockets présentée, il doit envoyer dans la réponse un entête <em>Sec-WebSocket-Version</em> correspondant à la ou les version-s supportée-s. Ici le guide explique la version 13, la plus récente à l'heure de l'écriture du tutoriel (<em>voir le tutoriel en version anglaise pour la date exacte ; il s'agit là d'une traduction</em>). Maintenant, nous allons passer à l'entête attendu : <em>Sec-WebSocket-Key</em>.</p> +> **Note :** Un grand nombre de navigateurs enverront un [`Entête d'origine`](/en-US/docs/HTTP/Access_control_CORS#Origin). Vous pouvez alors l'utiliser pour vérifier la sécurité de la transaction (par exemple vérifier la similitude des domaines, listes blanches ou noires, etc.) et éventuellement retourner une réponse [403 Forbidden](/en-US/docs/HTTP/Response_codes#403) si l'origine ne vous plaît pas. Toutefois garder à l'esprit que cet entête peut être simulé ou trompeur (il peut être ajouté manuellement ou lors du transfert). De nombreuses applications refusent les transactions sans celui-ci. -<div class="note"> -<p><strong>Note :</strong> Un grand nombre de navigateurs enverront un <a href="/en-US/docs/HTTP/Access_control_CORS#Origin"><code>Entête d'origine</code></a>. Vous pouvez alors l'utiliser pour vérifier la sécurité de la transaction (par exemple vérifier la similitude des domaines, listes blanches ou noires, etc.) et éventuellement retourner une réponse <a href="/en-US/docs/HTTP/Response_codes#403">403 Forbidden</a> si l'origine ne vous plaît pas. Toutefois garder à l'esprit que cet entête peut être simulé ou trompeur (il peut être ajouté manuellement ou lors du transfert). De nombreuses applications refusent les transactions sans celui-ci. </p> -</div> +> **Note :** L'URI de la requête (`/chat `dans notre cas), n'a pas de signification particulièrement dans les spécifications en usage : elle permet simplement, par convention, de disposer d'une multitude d'applications en parallèle grâce à WebSocket. Par exemple `exemple.com/chat` peut être associée à une API/une application de dialogue multiutilisateurs lorsque `/game` invoquera son homologue pour un jeu. -<div class="note"> -<p><strong>Note :</strong> L'URI de la requête (<code>/chat </code>dans notre cas), n'a pas de signification particulièrement dans les spécifications en usage : elle permet simplement, par convention, de disposer d'une multitude d'applications en parallèle grâce à WebSocket. Par exemple <code>exemple.com/chat</code> peut être associée à une API/une application de dialogue multiutilisateurs lorsque <code>/game</code> invoquera son homologue pour un jeu. </p> -</div> +> **Note :** [Les codes réguliers (_c-à-d défini par le protocole standard_) HTTP](/en-US/docs/HTTP/Response_codes) ne peuvent être utilisés qu'**_avant_** la poignée : ceux après la poignée, sont définis d'une manière spécifique dans la section 7.4 de la documentation sus-nommée. -<div class="note"> -<p><strong>Note:</strong> <a href="/en-US/docs/HTTP/Response_codes">Les codes réguliers (<em>c-à-d défini par le protocole standard</em>) HTTP</a> ne peuvent être utilisés qu'<strong><em>avant</em></strong> la poignée : ceux après la poignée, sont définis d'une manière spécifique dans la section 7.4 de la documentation sus-nommée. </p> -</div> +### La réponse du serveur lors de la poignée de mains -<h3 id="La_réponse_du_serveur_lors_de_la_poignée_de_mains">La réponse du serveur lors de la poignée de mains </h3> +Lorsqu'il reçoit la requête du client, le serveur doit envoyer une réponse correctement formée dans un format non-standard HTTP et qui ressemble au code ci-dessous. Gardez à l'esprit que chaque entête se termine par un saut de ligne : *\r\n* ; un saut de ligne doublé lors de l'envoi du dernier entête pour séparer du reste du corps (même si celui-ci est vide). -<p>Lorsqu'il reçoit la requête du client, le serveur doit envoyer une réponse correctement formée dans un format non-standard HTTP et qui ressemble au code ci-dessous. Gardez à l'esprit que chaque entête se termine par un saut de ligne : <em>\r\n</em> ; un saut de ligne doublé lors de l'envoi du dernier entête pour séparer du reste du corps (même si celui-ci est vide). </p> + HTTP/1.1 101 Switching Protocols + Upgrade: websocket + Connection: Upgrade + Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= -<pre><strong>HTTP/1.1 101 Switching Protocols</strong> -Upgrade: websocket -Connection: Upgrade -<strong>Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= +En sus, le serveur peut décider de proposer des extensions de protocoles ou des sous-protocoles à cet instant ; voir [Miscellaneous](#Miscellaneous) pour les détails. L'entête Sec-WebSocket-Accept nous intéresse ici : le serveur doit la former depuis l'entête Sec-WebSocket-Key envoyée précédemment par le client. Pour l'obtenir, vous devez concaténater (_rassembler_) la valeur de *Sec-WebSocket-Key* et "_258EAFA5-E914-47DA-95CA-C5AB0DC85B11_" (valeur fixée par défaut : c'est une "[magic string](https://en.wikipedia.org/wiki/Magic_string)") puis procéder au hash par la méthode [SHA-1](https://en.wikipedia.org/wiki/SHA-1) du résultat et retourner le format au format [base64](https://en.wikipedia.org/wiki/Base64). -</strong></pre> +> **Note :** Ce processus qui peut paraître inutilement complexe, permet de certifier que le serveur et le client sont bien sur une base WebSocket et non une requête HTTP (qui serait alors mal interprétée). -<p>En sus, le serveur peut décider de proposer des extensions de protocoles ou des sous-protocoles à cet instant ; voir <a href="#Miscellaneous">Miscellaneous</a> pour les détails. L'entête Sec-WebSocket-Accept nous intéresse ici : le serveur doit la former depuis l'entête Sec-WebSocket-Key envoyée précédemment par le client. Pour l'obtenir, vous devez concaténater (<em>rassembler</em>) la valeur de <em>Sec-WebSocket-Key</em> et "<em>258EAFA5-E914-47DA-95CA-C5AB0DC85B11</em>" (valeur fixée par défaut : c'est une "<a href="https://en.wikipedia.org/wiki/Magic_string">magic string</a>") puis procéder au hash par la méthode <a href="https://en.wikipedia.org/wiki/SHA-1">SHA-1</a> du résultat et retourner le format au format <a href="https://en.wikipedia.org/wiki/Base64">base64</a>. </p> +Ainsi si la clé (la valeur de l'entête du client) était "`dGhlIHNhbXBsZSBub25jZQ==`", le retour (_Accept \* dans la version d'origine du tutoriel_) sera : "`s3pPLMBiTxaQ9kYGzzhZRbK+xOo=`". Une fois que le serveur a envoyé les entêtes attendues, alors la poignée de mains est considérée comme effectuée et vous pouvez débuter l'échange de données ! -<div class="note"> -<p><strong>Note :</strong> Ce processus qui peut paraître inutilement complexe, permet de certifier que le serveur et le client sont bien sur une base WebSocket et non une requête HTTP (qui serait alors mal interprétée). </p> -</div> +> **Note :** Le serveur peut envoyer à ce moment, d'autres entêtes comme par exemple Set-Cookie, ou demander une authenficiation ou encore une redirection via les codes standards HTTP et ce **\*avant** \*la fin du processus de poignée de main. -<p>Ainsi si la clé (la valeur de l'entête du client) était "<code>dGhlIHNhbXBsZSBub25jZQ==</code>", le retour (<em>Accept * dans la version d'origine du tutoriel</em>) sera : "<code>s3pPLMBiTxaQ9kYGzzhZRbK+xOo=</code>". Une fois que le serveur a envoyé les entêtes attendues, alors la poignée de mains est considérée comme effectuée et vous pouvez débuter l'échange de données ! </p> +### Suivre les clients confirmés -<div class="note"> -<p><strong>Note :</strong> Le serveur peut envoyer à ce moment, d'autres entêtes comme par exemple Set-Cookie, ou demander une authenficiation ou encore une redirection via les codes standards HTTP et ce <em><strong>avant </strong></em>la fin du processus de poignée de main. </p> -</div> +Cela ne concerne pas directement le protocole WebSocket, mais mérite d'être mentionné maintenant : votre serveur pourra suivre le socket client : il ne faut donc pas tenter une poignée de mains supplémentaire avec un client déjà confirmé. Un même client avec la même IP pourrait alors se connecter à de multiples reprises, mais être finalement rejeté et dénié par le serveur si les tentatives sont trop nombreuses selon les règles pouvant être édictées pour éviter les attaques dites de [déni de service](https://en.wikipedia.org/wiki/Denial_of_service). -<h3 id="Suivre_les_clients_confirmés">Suivre les clients confirmés </h3> +## L'échange de trames de données -<p>Cela ne concerne pas directement le protocole WebSocket, mais mérite d'être mentionné maintenant : votre serveur pourra suivre le socket client : il ne faut donc pas tenter une poignée de mains supplémentaire avec un client déjà confirmé. Un même client avec la même IP pourrait alors se connecter à de multiples reprises, mais être finalement rejeté et dénié par le serveur si les tentatives sont trop nombreuses selon les règles pouvant être édictées pour éviter les attaques dites de <a href="https://en.wikipedia.org/wiki/Denial_of_service">déni de service</a>. </p> +Le client ou le serveur peuvent choisir d'envoyer un message à n'importe quel moment à partir de la fin du processus de poignée de mains : c'est la magie des WebSockets (une connexion permanente). Cependant, l'extraction d'informations à partir des trames de données n'est pas une expérience si... magique. Bien que toutes les trames suivent un même format spécifique, les données allant du client vers le serveur sont masquées en utilisant le [cryptage XOR](https://en.wikipedia.org/wiki/XOR_cipher) (avec une clé de 32 bits). L'article 5 de la spécification décrit en détail ce processus. -<h2 id="L'échange_de_trames_de_données">L'échange de trames de données </h2> +### Format -<p>Le client ou le serveur peuvent choisir d'envoyer un message à n'importe quel moment à partir de la fin du processus de poignée de mains : c'est la magie des WebSockets (une connexion permanente). Cependant, l'extraction d'informations à partir des trames de données n'est pas une expérience si... magique. Bien que toutes les trames suivent un même format spécifique, les données allant du client vers le serveur sont masquées en utilisant le <a href="https://en.wikipedia.org/wiki/XOR_cipher">cryptage XOR</a> (avec une clé de 32 bits). L'article 5 de la spécification décrit en détail ce processus. </p> +> **Attention :** Dans cette partie, `payload `équivaut en bon français à _charge utile_. C'est-à-dire les données qui ne font pas partie du fonctionnement de la trame mais de l'échange entre le serveur et le client. Ainsi j'ai traduit `payload data comme des données utiles. ` -<h3 id="Format">Format</h3> +Chaque trame (dans un sens ou dans un autre) suit le schéma suivant : -<div class="warning"> -<p><strong>Attention :</strong> Dans cette partie, <code>payload </code>équivaut en bon français à <em>charge utile</em>. C'est-à-dire les données qui ne font pas partie du fonctionnement de la trame mais de l'échange entre le serveur et le client. Ainsi j'ai traduit <code>payload data comme des <em>données utiles. </em></code></p> -</div> + 0 1 2 3 + 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 + +-+-+-+-+-------+-+-------------+-------------------------------+ + |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| | | + +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + 4 5 6 7 + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + | Extended payload length continued, if payload len == 127 | + + - - - - - - - - - - - - - - - +-------------------------------+ + 8 9 10 11 + + - - - - - - - - - - - - - - - +-------------------------------+ + | |Masking-key, if MASK set to 1 | + +-------------------------------+-------------------------------+ + 12 13 14 15 + +-------------------------------+-------------------------------+ + | Masking-key (continued) | Payload Data | + +-------------------------------- - - - - - - - - - - - - - - - + + : Payload Data continued ... : + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + | Payload Data continued ... | + +---------------------------------------------------------------+ -<p>Chaque trame (dans un sens ou dans un autre) suit le schéma suivant : </p> +RSV1-3 peuvent être ignorés, ils concernent les extensions. -<pre> <strong>0</strong> <strong>1</strong> <strong>2</strong> 3 - 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 -+-+-+-+-+-------+-+-------------+-------------------------------+ -|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| | | -+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + - 4 5 6 7 -+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + -| Extended payload length continued, if payload len == 127 | -+ - - - - - - - - - - - - - - - +-------------------------------+ - 8 9 <strong>10</strong> 11 -+ - - - - - - - - - - - - - - - +-------------------------------+ -| |Masking-key, if MASK set to 1 | -+-------------------------------+-------------------------------+ - 12 13 <strong>14</strong> 15 -+-------------------------------+-------------------------------+ -| Masking-key (continued) | Payload Data | -+-------------------------------- - - - - - - - - - - - - - - - + -: Payload Data continued ... : -+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + -| Payload Data continued ... | -+---------------------------------------------------------------+</pre> +Le masquage de bits indique simplement si le message a été codé. Les messages du client doivent être masquée, de sorte que votre serveur doit attendre qu'il soit à 1. (_l'article 5.1 de la spécification prévoit que votre serveur doit se déconnecter d'un client si celui-ci envoie un message non masqué_). Lors de l'envoi d'une trame au client, ne masquez pas et ne réglez pas le bit de masque - cela sera expliqué plus tard. -<p>RSV1-3 peuvent être ignorés, ils concernent les extensions. </p> +Note: Vous devez masquer les messages même lorsque vous utilisez un socket sécurisé. -<p>Le masquage de bits indique simplement si le message a été codé. Les messages du client doivent être masquée, de sorte que votre serveur doit attendre qu'il soit à 1. (<em>l'article 5.1 de la spécification prévoit que votre serveur doit se déconnecter d'un client si celui-ci envoie un message non masqué</em>). Lors de l'envoi d'une trame au client, ne masquez pas et ne réglez pas le bit de masque - cela sera expliqué plus tard.</p> +Le champ `opcode` définit comment est interpêtée la _charge utile_ (`payload data`) : ainsi `0x0` indique la consigne "continuer", `0x1` indique du texte (qui est systématiquement encodé en UTF-8), `0x2` pour des données binaires, et d'autres "codes de contrôle" qui seront évoqués plus tard. Dans cette version des WebSockets, `0x3` à 0x7 et `0xB` à `0xF` n'ont pas de significations particulières. -<p>Note: Vous devez masquer les messages même lorsque vous utilisez un socket sécurisé.</p> +Le bit FIN indique si c'est le dernier message de la série \[_NDT : pour la concaténation, pas la fin de la connexion elle-même_]. S'il est à 0, alors le serveur doit attendre encore une ou plusieurs parties. Sinon le message est considéré comme complet. -<p>Le champ <code>opcode</code> définit comment est interpêtée la <em>charge utile</em> (<code>payload data</code>) : ainsi <code>0x0</code> indique la consigne "continuer", <code>0x1</code> indique du texte (qui est systématiquement encodé en UTF-8), <code>0x2</code> pour des données binaires, et d'autres "codes de contrôle" qui seront évoqués plus tard. Dans cette version des WebSockets, <code>0x3</code> à 0x7 et <code>0xB</code> à <code>0xF</code> n'ont pas de significations particulières. </p> +### Connaître la taille des *données utiles* -<p>Le bit FIN indique si c'est le dernier message de la série [<em>NDT : pour la concaténation, pas la fin de la connexion elle-même</em>]. S'il est à 0, alors le serveur doit attendre encore une ou plusieurs parties. Sinon le message est considéré comme complet. </p> +Pour (pouvoir) lire les _données utiles_, vous devez savoir quand arrêter la lecture dans le flux des trames entrantes vers le serveur. C'est pourquoi il est important de connaître la taille des _données utiles_. Et malheureusement ce n'est pas toujours simple. Voici quelques étapes essentielles à connaître : -<h3 id="Connaître_la_taille_des_données_utiles">Connaître la taille des <em>données utiles </em></h3> +1. (_étape 1_) Lire tout d'abord les bits 9 à 15 (inclu) et les interprêter comme un entier non-signé. S'il équivaut à 125 ou moins, alors il correspond à la taille totale de la charge utile. + S'il vaut à 126, allez à l'étape 2 ou sinon, s'il vaut 127, allez à l'étape 3. +2. (_étape 2_) Lire les 16 bits supplémentaires et les interprêter comme précédent (entier non-signé). Vous avez alors la taille des données utiles. +3. (_étape 3_) Lire les 64 bits supplémentaires et les interprêter comme précédent (entier non-signé). Vous avez alors la taille des données utiles. Attention, le bit le plus significatif doit rester à 0. -<p>Pour (pouvoir) lire les <em>données utiles</em>, vous devez savoir quand arrêter la lecture dans le flux des trames entrantes vers le serveur. C'est pourquoi il est important de connaître la taille des <em>données utiles</em>. Et malheureusement ce n'est pas toujours simple. Voici quelques étapes essentielles à connaître : </p> +### Lire et démasquer les données -<ol> - <li>(<em>étape 1</em>) Lire tout d'abord les bits 9 à 15 (inclu) et les interprêter comme un entier non-signé. S'il équivaut à 125 ou moins, alors il correspond à la taille totale de la charge utile.<br> - S'il vaut à 126, allez à l'étape 2 ou sinon, s'il vaut 127, allez à l'étape 3. </li> - <li>(<em>étape 2</em>) Lire les 16 bits supplémentaires et les interprêter comme précédent (entier non-signé). Vous avez alors la taille des données utiles. </li> - <li>(<em>étape 3</em>) Lire les 64 bits supplémentaires et les interprêter comme précédent (entier non-signé). Vous avez alors la taille des données utiles. Attention, le bit le plus significatif doit rester à 0.</li> -</ol> +Si le bit MASK a été fixé (et il devrait l'être, pour les messages client-serveur), vous devez lire les 4 prochains octets (32 bits) : ils sont la clé de masquage. Une fois la longueur de charge utile connue et la clé de masquage décodée, vous pouvez poursuivre la lecture des autres bits comme étant les données utiles masquées. Par convention pour le reste du paragraphe, appelons-les _données encodées_, et la clé *masque*. Pour décoder les données, bouclez les octets du texte reçu en XOR avec l'octet du (_i modulo 4_) ième octet du *masque*. En voici le pseudo-code (_JavaScript valide_) : -<h3 id="Lire_et_démasquer_les_données">Lire et démasquer les données </h3> + var DECODED = ""; + for (var i = 0; i < ENCODED.length; i++) { + DECODED[i] = ENCODED[i] ^ MASK[i % 4]; + } -<p>Si le bit MASK a été fixé (et il devrait l'être, pour les messages client-serveur), vous devez lire les 4 prochains octets (32 bits) : ils sont la clé de masquage. Une fois la longueur de charge utile connue et la clé de masquage décodée, vous pouvez poursuivre la lecture des autres bits comme étant les données utiles masquées. Par convention pour le reste du paragraphe, appelons-les <em>données encodées</em>, et la clé <em>masque</em>. Pour décoder les données, bouclez les octets du texte reçu en XOR avec l'octet du (<em>i modulo 4</em>) ième octet du <em>masque</em>. En voici le pseudo-code (<em>JavaScript valide</em>) : </p> +> **Note :** Ici la variable `DECODED` correspond aux données utiles à votre application - en fonction de l'utilisation ou non d'un sous-protocole (_si c'est `json`, vous devez encore décoder les données utiles reçues avec le parseur JSON_). -<pre>var DECODED = ""; -for (var i = 0; i < ENCODED.length; i++) { - DECODED[i] = ENCODED[i] ^ MASK[i % 4]; -}</pre> +### La fragmentation des messages -<div class="note"> -<p><strong>Note :</strong> Ici la variable <code>DECODED</code> correspond aux données utiles à votre application - en fonction de l'utilisation ou non d'un sous-protocole (<em>si c'est <code>json</code>, vous devez encore décoder les données utiles reçues avec le parseur JSON</em>). </p> -</div> +Les champs FIN et opcodes fonctionnent ensemble pour envoyer un message découpé en une multitude de trames. C'est ce que l'on appele la _fragmentation des messages_. La fragmentation est seulement possible avec les opcodes de `0x0 `à `0x2`. -<h3 id="La_fragmentation_des_messages">La fragmentation des messages </h3> +Souvenez-vous de l'intérêt de l'opcode et ce qu'il implique dans l'échange des trames. Pour _0x1_ c'est du texte, pour _0x2_ des données binaires, etc. Toutefois pour _0x0_, la frame est dite "continue" (elle s'ajoute à la précédente). En voici un exemple plus clair, où il y a en réalité deux textes de message (sur 4 trames différentes) : -<p>Les champs FIN et opcodes fonctionnent ensemble pour envoyer un message découpé en une multitude de trames. C'est ce que l'on appele la <em>fragmentation des messages</em>. La fragmentation est seulement possible avec les opcodes de <code>0x0 </code>à <code>0x2</code>. </p> + Client: FIN=1, opcode=0x1, msg="hello" + Server: (process complete message immediately) Hi. + Client: FIN=0, opcode=0x1, msg="and a" + Server: (listening, new message containing text started) + Client: FIN=0, opcode=0x0, msg="happy new" + Server: (listening, payload concatenated to previous message) + Client: FIN=1, opcode=0x0, msg="year!" + Server: (process complete message) Happy new year to you too! -<p>Souvenez-vous de l'intérêt de l'opcode et ce qu'il implique dans l'échange des trames. Pour <em>0x1 </em>c'est du texte, pour <em>0x2 </em>des données binaires, etc. Toutefois pour <em>0x0</em>, la frame est dite "continue" (elle s'ajoute à la précédente). En voici un exemple plus clair, où il y a en réalité deux textes de message (sur 4 trames différentes) : </p> +La première trame dispose d'un message en entier (FIN = 1 et optcode est différent de 0x0) : le serveur peut traiter la requête reçue et y répondre. A partir de la seconde trame et pour les deux suivantes (soit trois trames), l'opcode à 0x1 puis 0x0 signifie qu'il s'agit d'un texte suivi du reste du contenu (0x1 = texte ; 0x0 = la suite). La 3e trame à FIN = 1 indique la fin de la requête. +Voir la [section 5.4](http://tools.ietf.org/html/rfc6455#section-5.4) de la spécification pour les détails de cette partie. -<pre><strong>Client:</strong> FIN=1, opcode=0x1, msg="hello" -<strong>Server:</strong> <em>(process complete message immediately) </em>Hi. -<strong>Client:</strong> FIN=0, opcode=0x1, msg="and a" -<strong>Server:</strong> <em>(listening, new message containing text started)</em> -<strong>Client:</strong> FIN=0, opcode=0x0, msg="happy new" -<strong>Server:</strong> <em>(listening, payload concatenated to previous message)</em> -<strong>Client:</strong> FIN=1, opcode=0x0, msg="year!" -<strong>Server:</strong> <em>(process complete message) </em>Happy new year to you too!</pre> +## Pings-Pongs : le "coeur" des WebSockets -<p>La première trame dispose d'un message en entier (FIN = 1 et optcode est différent de 0x0) : le serveur peut traiter la requête reçue et y répondre. A partir de la seconde trame et pour les deux suivantes (soit trois trames), l'opcode à 0x1 puis 0x0 signifie qu'il s'agit d'un texte suivi du reste du contenu (0x1 = texte ; 0x0 = la suite). La 3e trame à FIN = 1 indique la fin de la requête. <br> - Voir la <a href="http://tools.ietf.org/html/rfc6455#section-5.4">section 5.4</a> de la spécification pour les détails de cette partie. </p> +A n'importe quel moment après le processus de poignée de mains, le client ou le serveur peut choisir d'envoyer un _ping_ à l'autre partie. Lorsqu'il est reçu, l'autre partie doit renvoyer dès possible un _pong_. Cette pratique permet de vérifier et de maintenir la connexion avec le client par exemple. -<h2 id="Pings-Pongs_le_coeur_des_WebSockets">Pings-Pongs : le "coeur" des WebSockets</h2> +Le _ping_ ou le _pong_ sont des trames classiques dites **de contrôle**. Les _pings_ disposent d'un opcode à `0x9` et les _pongs_ à `0xA`. Lorsqu'un _ping_ est envoyé, le _pong_ doit disposer de la même donnée utile en réponse que le ping (et d'une taille maximum autorisé de 125). Le _pong_ seul (c-à-d sans _ping_) est ignoré. -<p>A n'importe quel moment après le processus de poignée de mains, le client ou le serveur peut choisir d'envoyer un <em>ping </em>à l'autre partie. Lorsqu'il est reçu, l'autre partie doit renvoyer dès possible un <em>pong</em>. Cette pratique permet de vérifier et de maintenir la connexion avec le client par exemple. </p> +> **Note :** Lorsque plusieurs pings sont envoyés à la suite, un **seul** pong suffit en réponse (_le plus récent pour la donnée utile renvoyée_). -<p>Le <em>ping </em>ou le <em>pong </em>sont des trames classiques dites <strong>de contrôle</strong>. Les <em>pings </em>disposent d'un opcode à <code>0x9</code> et les <em>pongs </em>à <code>0xA</code>. Lorsqu'un <em>ping </em>est envoyé, le <em>pong </em>doit disposer de la même donnée utile en réponse que le ping (et d'une taille maximum autorisé de 125). Le <em>pong </em>seul (c-à-d sans <em>ping</em>) est ignoré. </p> +## Clore la connexion -<div class="note"> -<p><strong>Note :</strong> Lorsque plusieurs pings sont envoyés à la suite, un <strong>seul </strong>pong suffit en réponse (<em>le plus récent pour la donnée utile renvoyée</em>). </p> -</div> +La connexion peut être close à l'initiative du client ou du serveur grâce à l'envoi d'une trame de contrôle contenant des données spécifiques permettant d'interrompre la poignée de main (de lever définitivement le masque pour être plus précis ; voir la [section 5.5.1](http://tools.ietf.org/html/rfc6455#section-5.5.1)). Dès la réception de la trame, le récepteur envoit une trame spécifique de fermeture en retour (pour signifier la bonne compréhension de la fin de connexion). C'est l'émetteur à l'origine de la fermeture qui doit clore la connexion ; toutes les données supplémentaires sont éliminés / ignorés. -<h2 id="Clore_la_connexion">Clore la connexion </h2> +## Diverses informations utiles -<p>La connexion peut être close à l'initiative du client ou du serveur grâce à l'envoi d'une trame de contrôle contenant des données spécifiques permettant d'interrompre la poignée de main (de lever définitivement le masque pour être plus précis ; voir la <a href="http://tools.ietf.org/html/rfc6455#section-5.5.1">section 5.5.1</a>). Dès la réception de la trame, le récepteur envoit une trame spécifique de fermeture en retour (pour signifier la bonne compréhension de la fin de connexion). C'est l'émetteur à l'origine de la fermeture qui doit clore la connexion ; toutes les données supplémentaires sont éliminés / ignorés. </p> +> **Note :** L'ensemble des codes, extensions et sous-protocoles liés aux WebSocket sont enregistrés dans le (registre) [IANA WebSocket Protocol Registry](http://www.iana.org/assignments/websocket/websocket.xml). -<h2 id="Diverses_informations_utiles">Diverses informations utiles</h2> +Les extensions et sous-protocoles des WebSockets sont négociés durant [l'échange des entêtes de la poignée de mains](#PoignéeDeMain). Si l'on pourrait croire qu'extensions et sous-protocles sont finalement la même chose, il n'en est rien : **le contrôle des extensions agit sur les trames** ce qui modifie la charge utile ; **alors que les sous-protocoles modifient uniquement la charge utile,** et rien d'autre. Les extensions sont optionnelles et généralisées (par exemple pour la compression des données) ; les sous-protocoles sont souvent obligatoires et ciblés (par exemple dans le cadre d'une application de chat ou d'un jeu MMORPG). -<div class="note"> -<p><strong>Note :</strong> L'ensemble des codes, extensions et sous-protocoles liés aux WebSocket sont enregistrés dans le (registre) <a href="http://www.iana.org/assignments/websocket/websocket.xml">IANA WebSocket Protocol Registry</a>.</p> -</div> +> **Attention :** Les sous-extensions ou les sous-protocoles ne sont pas obligatoires pour l'échange de données par WebSockets ; mais l'esprit développé ici est de rendre soit plus efficace ou sécurisée la transmission (l'esprit d'une extension) ; soit de délimiter et de normaliser le contenu de l'échange (l'esprit d'un sous-protocole ; qui étend donc le protocole par défaut des WebSockets qu'est l'échange de texte simple au format UTF-8). -<p>Les extensions et sous-protocoles des WebSockets sont négociés durant <a href="#PoignéeDeMain">l'échange des entêtes de la poignée de mains</a>. Si l'on pourrait croire qu'extensions et sous-protocles sont finalement la même chose, il n'en est rien : <strong>le contrôle des extensions agit sur les trames</strong> ce qui modifie la charge utile ; <strong>alors que les sous-protocoles modifient uniquement la charge utile,</strong> et rien d'autre. Les extensions sont optionnelles et généralisées (par exemple pour la compression des données) ; les sous-protocoles sont souvent obligatoires et ciblés (par exemple dans le cadre d'une application de chat ou d'un jeu MMORPG). </p> +### Les extensions -<div class="warning"> -<p><strong>Attention :</strong> Les sous-extensions ou les sous-protocoles ne sont pas obligatoires pour l'échange de données par WebSockets ; mais l'esprit développé ici est de rendre soit plus efficace ou sécurisée la transmission (l'esprit d'une extension) ; soit de délimiter et de normaliser le contenu de l'échange (l'esprit d'un sous-protocole ; qui étend donc le protocole par défaut des WebSockets qu'est l'échange de texte simple au format UTF-8). </p> -</div> +L'idée des extensions pourrait être, par exemple, la compression d'un fichier avant de l'envoyer par courriel / email à quelqu'un : les données transférées ne changent pas de contenu, mais leur format oui (et leur taille aussi...). Ce n'est donc pas le format du contenu qui change que le mode transmission - c'est le principe des extensions en WebSockets, dont le principe de base est d'être un protocole simple d'échange de données. -<h3 id="Les_extensions">Les extensions</h3> +> **Note :** Les extensions sont présentées et expliquées dans les sections 5.8, 9, 11.3.2, and 11.4 de la documentation sus-nommées. -<p>L'idée des extensions pourrait être, par exemple, la compression d'un fichier avant de l'envoyer par courriel / email à quelqu'un : les données transférées ne changent pas de contenu, mais leur format oui (et leur taille aussi...). Ce n'est donc pas le format du contenu qui change que le mode transmission - c'est le principe des extensions en WebSockets, dont le principe de base est d'être un protocole simple d'échange de données. </p> +### Les sous-protocoles -<div class="note"> -<p><strong>Note :</strong> Les extensions sont présentées et expliquées dans les sections 5.8, 9, 11.3.2, and 11.4 de la documentation sus-nommées.</p> -</div> +Les sous-protocoles sont à comparer à [un schéma XML](https://en.wikipedia.org/wiki/XML_schema) ou [une déclaration de DocType](https://en.wikipedia.org/wiki/Document_Type_Definition). Ainsi vous pouvez utiliser seulement du XML et sa syntaxe et, imposer par le biais des sous-protocoles, son utilisation durant l'échange WebSocket. C'est l'intérêt de ces sous-protocoles : établir une structure définie (_et intangible : le client se voit imposer la mise en oeuvre par le serveur_), bien que les deux doivent l'accepter pour communiquer ensemble. -<h3 id="Les_sous-protocoles">Les sous-protocoles </h3> +> **Note :** Les sous-protocoles sont expliqués dans les sections 1.9, 4.2, 11.3.4, and 11.5 de la documentation sus-nommés. -<p>Les sous-protocoles sont à comparer à <a href="https://en.wikipedia.org/wiki/XML_schema">un schéma XML</a> ou <a href="https://en.wikipedia.org/wiki/Document_Type_Definition">une déclaration de DocType</a>. Ainsi vous pouvez utiliser seulement du XML et sa syntaxe et, imposer par le biais des sous-protocoles, son utilisation durant l'échange WebSocket. C'est l'intérêt de ces sous-protocoles : établir une structure définie (<em>et intangible : le client se voit imposer la mise en oeuvre par le serveur</em>), bien que les deux doivent l'accepter pour communiquer ensemble. </p> +Exemple : un client souhaite demander un sous-protocole spécifique. Pour se faire, il envoie dans les entêtes d'origine du processus de poignées de mains : -<div class="note"> -<p><strong>Note :</strong> Les sous-protocoles sont expliqués dans les sections 1.9, 4.2, 11.3.4, and 11.5 de la documentation sus-nommés. </p> -</div> + GET /chat HTTP/1.1 + ... + Sec-WebSocket-Protocol: soap, wamp -<p>Exemple : un client souhaite demander un sous-protocole spécifique. Pour se faire, il envoie dans les entêtes d'origine du processus de poignées de mains : </p> +Ou son équivalent : -<pre>GET /chat HTTP/1.1 -... -Sec-WebSocket-Protocol: soap, wamp -</pre> + ... + Sec-WebSocket-Protocol: soap + Sec-WebSocket-Protocol: wamp -<p>Ou son équivalent : </p> +Le serveur doit désormais choisir l'un des protocoles suggérés par le client et qu'il peut prendre en charge. S'il peut en prendre plus d'un, le premier envoyé par le client sera privilégié. Dans notre exemple, le client envoit `soap `et `wamp`, le serveur qui supporte les deux enverra donc : -<pre>... -Sec-WebSocket-Protocol: soap -Sec-WebSocket-Protocol: wamp -</pre> + Sec-WebSocket-Protocol: soap -<p>Le serveur doit désormais choisir l'un des protocoles suggérés par le client et qu'il peut prendre en charge. S'il peut en prendre plus d'un, le premier envoyé par le client sera privilégié. Dans notre exemple, le client envoit <code>soap </code>et <code>wamp</code>, le serveur qui supporte les deux enverra donc : </p> +> **Attention :** Le serveur ne peut (ne doit) envoyer plus d'un entête `Sec-Websocket-Protocol`. **S'il n'en supporte aucun, il ne doit pas renvoyer l'entête `Sec-WebSocket-Protocol` (l'entête vide n'est pas correct).** Le client peut alors interrompre la connexion s'il n'a pas le sous-protocole qu'il souhaite (ou qu'il supporte). -<pre>Sec-WebSocket-Protocol: soap -</pre> +Si vous souhaitez que votre serveur puisse supporter certains sous-protocoles, vous pourriez avoir besoin d'une application ou de scripts supplémentaires sur le serveur. Imaginons par exemple que vous utilisiez le sous-protocole json - où toutes les données échangées par WebSockets sont donc formatés suivant le format [JSON](https://fr.wikipedia.org/wiki/JavaScript_Object_Notation). Si le client sollicite ce sous-protocole et que le serveur souhaite l'accepter, vous **devez disposer** d'un parseur (d'un décodeur) JSON et décoder les données par celui-ci. -<div class="warning"> -<p><strong>Attention :</strong> Le serveur ne peut (ne doit) envoyer plus d'un entête <code>Sec-Websocket-Protocol</code>. <strong>S'il n'en supporte aucun, il ne doit pas renvoyer l'entête <code>Sec-WebSocket-Protocol</code> (l'entête vide n'est pas correct). </strong>Le client peut alors interrompre la connexion s'il n'a pas le sous-protocole qu'il souhaite (ou qu'il supporte). </p> -</div> +> **Note :** Pour éviter des conflits d'espaces de noms, il est recommandé d'utiliser le sous-protocole comme un sous-domaine de celui utilisé. Par exemple si vous utilisez un sous-protocole propriétaire qui utilise un format d'échange de données non-standard pour une application de _chat_ sur le domaine _exemple.com_, vous devrirez utiliser : `Sec-WebSocket-Protocol: chat.exemple.com`. S'il y a différentes versions possibles, modifiez le chemin pour faire correspondre le path à votre version comme ceci : `chat.exemple.com/2.0`. Notez que ce n'est pas obligatoire, c'est une convention d'écriture optionnel et qui peut être utilisée d'une toute autre façon. -<p>Si vous souhaitez que votre serveur puisse supporter certains sous-protocoles, vous pourriez avoir besoin d'une application ou de scripts supplémentaires sur le serveur. Imaginons par exemple que vous utilisiez le sous-protocole json - où toutes les données échangées par WebSockets sont donc formatés suivant le format <a href="https://fr.wikipedia.org/wiki/JavaScript_Object_Notation">JSON</a>. Si le client sollicite ce sous-protocole et que le serveur souhaite l'accepter, vous <strong>devez disposer</strong> d'un parseur (d'un décodeur) JSON et décoder les données par celui-ci. </p> +## Contenus associés -<div class="note"> -<p><strong>Note :</strong> Pour éviter des conflits d'espaces de noms, il est recommandé d'utiliser le sous-protocole comme un sous-domaine de celui utilisé. Par exemple si vous utilisez un sous-protocole propriétaire qui utilise un format d'échange de données non-standard pour une application de <em>chat </em>sur le domaine <em>exemple.com</em>, vous devrirez utiliser : <code>Sec-WebSocket-Protocol: chat.exemple.com</code>. S'il y a différentes versions possibles, modifiez le chemin pour faire correspondre le path à votre version comme ceci : <code>chat.exemple.com/2.0</code>. Notez que ce n'est pas obligatoire, c'est une convention d'écriture optionnel et qui peut être utilisée d'une toute autre façon.</p> -</div> - -<h2 id="Contenus_associés">Contenus associés</h2> - -<ul> - <li><a href="/en-US/docs/WebSockets/Writing_WebSocket_server">Tutorial: Websocket server in C#</a></li> - <li><a href="/en-US/docs/WebSockets/Writing_WebSocket_client_applications">Writing WebSocket client applications</a></li> - <li><a href="/en-US/docs/WebSockets/WebSocket_Server_Vb.NET">Tutorial: Websocket server in VB.NET</a></li> -</ul> +- [Tutorial: Websocket server in C#](/en-US/docs/WebSockets/Writing_WebSocket_server) +- [Writing WebSocket client applications](/en-US/docs/WebSockets/Writing_WebSocket_client_applications) +- [Tutorial: Websocket server in VB.NET](/en-US/docs/WebSockets/WebSocket_Server_Vb.NET) |