diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:41:45 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:41:45 -0500 |
commit | 1109132f09d75da9a28b649c7677bb6ce07c40c0 (patch) | |
tree | 0dd8b084480983cf9f9680e8aedb92782a921b13 /files/es/web/api/websockets_api | |
parent | 4b1a9203c547c019fc5398082ae19a3f3d4c3efe (diff) | |
download | translated-content-1109132f09d75da9a28b649c7677bb6ce07c40c0.tar.gz translated-content-1109132f09d75da9a28b649c7677bb6ce07c40c0.tar.bz2 translated-content-1109132f09d75da9a28b649c7677bb6ce07c40c0.zip |
initial commit
Diffstat (limited to 'files/es/web/api/websockets_api')
4 files changed, 859 insertions, 0 deletions
diff --git a/files/es/web/api/websockets_api/escribiendo_servidor_websocket/index.html b/files/es/web/api/websockets_api/escribiendo_servidor_websocket/index.html new file mode 100644 index 0000000000..333e8e8830 --- /dev/null +++ b/files/es/web/api/websockets_api/escribiendo_servidor_websocket/index.html @@ -0,0 +1,244 @@ +--- +title: Escribiendo un servidor WebSocket en C# +slug: Web/API/WebSockets_API/Escribiendo_servidor_WebSocket +tags: + - HTML5 + - Tutorial + - WebSockets +translation_of: Web/API/WebSockets_API/Writing_WebSocket_server +--- +<h2 id="Introducción">Introducción</h2> + +<p>Si deseas utilizar la API WebSocket, es conveniente si tienes un servidor. En este artículo te mostraré como puedes escribir uno en C#. Tú puedes hacer esto en cualquier lenguaje del lado del servidor, pero para mantener las cosas simples y más comprensibles, elegí el lenguaje de Microsoft<span style="line-height: 1.5;">.</span></p> + +<p>Este servidor se ajusta a <a href="http://tools.ietf.org/html/rfc6455" title="http://tools.ietf.org/html/rfc6455">RFC 6455</a> por lo que solo manejará las conexiones de Chrome version 16, Firefox 11, IE 10 and superiores.</p> + +<h2 id="Primeros_pasos">Primeros pasos</h2> + +<p>WebSocket se comunica a través de conexiones <a href="https://es.wikipedia.org/wiki/Transmission_Control_Protocol" title="https://es.wikipedia.org/wiki/Transmission_Control_Protocol">TCP (Transmission Control Protocol)</a>, afortunadamente C# tiene una clase <a href="http://msdn.microsoft.com/es-es/library/system.net.sockets.tcplistener.aspx" title="http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.aspx">TcpListener</a> la cual hace lo que su nombre sugiere. Esta se encuentra en el namespace <em>System.Net.Sockets</em>.</p> + +<div class="note"> +<p><span style="line-height: 1.572;">Es una buena idea usar la instrucción <code>using</code></span><span style="line-height: 1.572;"> para escribir menos. Eso significa que no tendrás que re escribir el namespace de nuevo en cada ocasión.</span></p> +</div> + +<h3 id="TcpListener">TcpListener</h3> + +<p>Constructor:</p> + +<pre class="brush: cpp">TcpListener(System.Net.IPAddress localaddr, int port)</pre> + +<p><code>localaddr</code> especifica la IP a escuchar y <code>port</code> especifica el puerto.</p> + +<div class="note"> +<p>Para crear un objeto <code>IPAddress</code> desde un <code>string</code>, usa el método estático <code>Parse</code> de <code>IPAddres.</code></p> +</div> + +<p><span style="line-height: 1.572;">Métodos</span><span style="line-height: 1.572;">:</span></p> + +<ul> + <li><code><span style="line-height: 1.572;">Start()</span></code></li> + <li><span style="line-height: 1.572;">S<code>ystem.Net.Sockets.<a href="http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.aspx" title="http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.aspx">TcpClient</a> AcceptTcpClient()</code><br> + Espera por una conexión TCP, la acepta y la devuelve como un objeto TcpClient.</span></li> +</ul> + +<p><span style="line-height: 1.572;">Aquí está como utilizar lo que hemos aprendido:</span></p> + +<pre class="brush: cpp">using System.Net.Sockets; +using System.Net; +using System; + +class Server { + public static void Main() { + TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 80); + + server.Start(); + Console.WriteLine("El server se ha iniciado en 127.0.0.1:80.{0}Esperando una conexión...", Environment.NewLine); + + TcpClient client = server.AcceptTcpClient(); + + Console.WriteLine("Un cliente conectado."); + } +} +</pre> + +<h3 id="TcpClient"><span style="line-height: 1.572;">TcpClient</span></h3> + +<p>Métodos:</p> + +<ul> + <li><code>System.Net.Sockets.<a href="http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.aspx" title="http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.aspx">NetworkStream</a> GetStream()</code><br> + Obtiene el stream del canal de comunicación. Ambos lados del canal tienen capacidad de lectura y escritura.</li> +</ul> + +<p>Propiedades:</p> + +<ul> + <li><code>int Available</code><br> + Este es el número de bytes de datos que han sido enviados. El valor es cero hasta que <code><em>NetworkStream.DataAvailable</em></code> es <code><em>true</em></code>.</li> +</ul> + +<h3 id="NetworkStream">NetworkStream</h3> + +<p>Métodos:</p> + +<pre class="brush: cpp">Write(Byte[] buffer, int offset, int size)</pre> + +<p>Escribe bytes desde el <em>buffer;</em> el <em>offset</em> y el <em>size</em> determinan la longitud del mensaje.</p> + +<pre><span class="brush: cpp" style="line-height: 1.572;">Read(Byte[] buffer, int offset, int size)</span></pre> + +<p>Lee bytes al <em>buffer;</em> el <em>offset</em> y el <em>size </em>determinan la longitud del mensaje.</p> + +<p>Ampliemos nuestro ejemplo anterior.</p> + +<pre class="brush: cpp">TcpClient client = server.AcceptTcpClient(); + +Console.WriteLine("Un cliente conectado."); + +NetworkStream stream = client.GetStream(); + +//enter to an infinite cycle to be able to handle every change in stream +while (true) { + while (!stream.DataAvailable); + + Byte[] bytes = new Byte[client.Available]; + + stream.Read(bytes, 0, bytes.Length); +}</pre> + +<h2 id="Handshaking">Handshaking</h2> + +<p>Cuando un cliente se conecta al servidor, envía una solicitud GET para actualizar la conexión al WebSocket desde una simple petición HTTP. Esto es conocido como <em>handshaking</em>.</p> + +<p>Este código de ejemplo detecta el GET desde el cliente. Nota que esto bloqueará hasta los 3 primeros bytes del mensaje disponible. Soluciones alternativas deben ser investigadas para ambientes de producción.</p> + +<pre><code>using System.Text; +using System.Text.RegularExpressions; + +while(client.Available < 3) +{ + // wait for enough bytes to be available +} + +Byte[] bytes = new Byte[client.Available]; + +stream.Read(bytes, 0, bytes.Length); + +//translate bytes of request to string +String data = Encoding.UTF8.GetString(bytes); + +if (Regex.IsMatch(data, "^GET")) { + +} else { + +}</code></pre> + +<p>Esta respuesta es fácil de construir, pero puede ser un poco díficil de entender. La explicación completa del <em>handshake </em>al servidor puede encontrarse en <a href="https://developer.mozilla.org/es/docs/WebSockets-840092-dup/RFC%206455,%20section%204.2.2">RFC 6455, section 4.2.2</a>. Para nuestros propósitos, solo construiremos una respuesta simple.</p> + +<p>Debes:</p> + +<ol> + <li>Obtener el valor de "<em>Sec-WebSocket-Key" </em>sin espacios iniciales ni finales de el encabezado de la solicitud</li> + <li>Concatenarlo con "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"</li> + <li>Calcular el código SHA-1 y Base64</li> + <li>Escribe el valor <em>Sec-WebSocket-Accept</em> en el encabezado como parte de la respuesta HTTP.</li> +</ol> + +<pre class="brush: cpp">if (new Regex("^GET").IsMatch(data)) { + Byte[] response = Encoding.UTF8.GetBytes("HTTP/1.1 101 Switching Protocols" + Environment.NewLine + + "Connection: Upgrade" + Environment.NewLine + + "Upgrade: websocket" + Environment.NewLine + + "Sec-WebSocket-Accept: " + Convert.ToBase64String ( + SHA1.Create().ComputeHash ( + Encoding.UTF8.GetBytes ( + new Regex("Sec-WebSocket-Key: (.*)").Match(data).Groups[1].Value.Trim() + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" + ) + ) + ) + Environment.NewLine + + Environment.NewLine); + + stream.Write(response, 0, response.Length); +} +</pre> + +<h2 id="Decoding_messages">Decoding messages</h2> + +<p>Luego de un <em>handshake</em> exitoso el cliente puede enviar mensajes al servidor, pero estos serán codificados.</p> + +<p>Si nosotros enviamos "MDN", obtendremos estos bytes:</p> + +<table> + <tbody> + <tr> + <td>129</td> + <td>131</td> + <td>61</td> + <td>84</td> + <td>35</td> + <td>6</td> + <td>112</td> + <td>16</td> + <td>109</td> + </tr> + </tbody> +</table> + +<p>- 129:</p> + +<table> + <thead> + <tr> + <th scope="col">FIN (¿Es el mensaje completo?)</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> + +<p>FIN: Puedes enviar tu mensaje en marcos, pero ahora debe mantener las cosas simples.<br> + <span style="line-height: 1.572;">Opcode </span><em>0x1</em><span style="line-height: 1.572;"> significa que es un texto. </span><a href="http://tools.ietf.org/html/rfc6455#section-5.2" style="line-height: 1.572;" title="http://tools.ietf.org/html/rfc6455#section-5.2">Lista completa de Opcodes</a></p> + +<p>- 131:</p> + +<p>Si el segundo byte menos 128 se encuentra entre 0 y 125, esta es la longitud del mensaje. Si es 126, los siguientes 2 bytes (entero sin signo de 16 bits), si es 127, los siguientes 8 bytes (entero sin signo de 64 bits) son la longitud.</p> + +<div class="note"> +<p>Puedo tomar 128, porque el primer bit siempre es 1.</p> +</div> + +<p>- 61, 84, 35 y 6 son los bytes de la clave a decodificar. Cambian en cada oportunidad.</p> + +<p>- Los bytes codificados restantes son el mensaje<span style="line-height: 1.572;">.</span></p> + +<h3 id="Algoritmo_de_decodificación">Algoritmo de decodificación</h3> + +<p>byte decodificado = byte codificado XOR (posición del byte codificado Mod 4) byte de la clave</p> + +<p>Ejemplo en C#:</p> + +<pre class="brush: cpp">Byte[] decoded = new Byte[3]; +Byte[] encoded = new Byte[3] {112, 16, 109}; +Byte[] key = Byte[4] {61, 84, 35, 6}; + +for (int i = 0; i < encoded.Length; i++) { + decoded[i] = (Byte)(encoded[i] ^ key[i % 4]); +}</pre> + +<h2 id="Relacionado">Relacionado</h2> + +<ul> + <li><a href="/es/docs/WebSockets/Writing_WebSocket_servers">Escribiendo servidores WebSocket</a></li> +</ul> + +<div id="cke_pastebin" style="position: absolute; top: 2209.23px; width: 1px; height: 1px; overflow: hidden; left: -1000px;"> </div> diff --git a/files/es/web/api/websockets_api/escribiendo_servidores_con_websocket/index.html b/files/es/web/api/websockets_api/escribiendo_servidores_con_websocket/index.html new file mode 100644 index 0000000000..1261f75bec --- /dev/null +++ b/files/es/web/api/websockets_api/escribiendo_servidores_con_websocket/index.html @@ -0,0 +1,246 @@ +--- +title: Escribir servidores WebSocket +slug: Web/API/WebSockets_API/Escribiendo_servidores_con_WebSocket +translation_of: Web/API/WebSockets_API/Writing_WebSocket_servers +--- +<p>{{gecko_minversion_header("2")}}</p> + +<h2 id="Introducción">Introducción</h2> + +<p>Un servidor WebSocket es simplemente una aplicación TCP que escucha en cualquier puerto de un servidor que sigue un protocolo específico. La tarea de crear un servidor propio personalizado suele asustar a los desarrolladores, sin embargo puede resultar muy fácil implementar un servidor WebSocket en la plataforma que elijas.</p> + +<p>Un servidor WebSocket puede ser escrito en cualquier lenguaje de programación Server-Side que sea soporte <a href="https://en.wikipedia.org/wiki/Berkeley_sockets">Berkeley Sockets</a>, como por ejemplo C++ o Python o inclusive PHP y JavaScript para servidores. Este no va a ser un tutorial para ningún lenguaje espefícamente sino que te ayudará a escribir tu propio servidor.<br> + <br> + Necesitarás conocer como trabaja el protocolo HTTP y una experiencia intermedia en programación. Dependiendo de las capacidades de tu lenguaje puede ser necesario tener conocimientos en sockets TCP. Esta guía te dará el conocimiento necesario para escribir un servidor con WebSocket.</p> + +<div class="note"> +<p>Lea las últimas especificaciones oficiales de WebSocket <a href="http://datatracker.ietf.org/doc/rfc6455/?include_text=1">RFC 6455</a>. Las secciones 1 y 4-7 son especialmente interesantes para personas que deseen implementar servidores. La sección 10 abarca temas de seguridad y definitivamente deberías leerla antes de exponer tu servidor a la red.</p> +</div> + +<p>Un servidor WebSocket es explicado a un muy bajo nivel aquí. Los servidores WebSocket usualmente estan separados y especializados (por una cuestión de balance de cargas y otra razones prácticas), por lo tanto deberías usar un <a href="https://en.wikipedia.org/wiki/Reverse_proxy">Reverse Proxy</a> (semejante a un servidor HTTP común) casi siempre para detectar los Handshakes de WebSocket, preprocesarlos, y reenviar los datos de los clientes al servidor WebSocket real.<br> + </p> + +<h2 id="Paso_1_El_Handshake_del_WebSocket"><a name="Handshake">Paso 1: El Handshake del WebSocket </a></h2> + +<p>Antes que nada, el servidor debe escuchar las conexiones entrantes usando un socket TCP estandar. Dependiendo de tu plataforma, esto puede ser manejado por tí. Por ejemplo asumamos que tu servidor esta escuchando la dirección example.com en el puerto 8000, y tu socket en el servidor responde a la petición GET con /chat.</p> + +<div class="warning"> +<p><strong>Advertencia: </strong>El servidor puede escuchar cualquier puerto que elijas, pero si elijes un puerto diferente al 80 o 443 podría haber problemas con los firewalls y proxies. Suele suceder con el puerto 443 tambien pero para eso se necesita un conexión segura (TLS/SSL). También se debe aclarar que la mayoría de los navegadores (como Firefox 8 o superiores) no permiten conexiones a servidores WebSocket sin seguridad que se realicen desde páginas web con seguridad (HTTPS). </p> +</div> + +<p>El Handshake es el puente desde HTTP a WS. En el Handshake se negocian los detalles de la conexión y cualquier de las partes pueden abandonar el proceso antes de completar dicha conexión si los términos no son favorables. El servidor debe ser cuidadoso al analizar lo que el cliente pide, de lo contrario podrían introducirse problemas de seguridad.</p> + +<h3 id="Petición_de_Handshake_en_el_cliente">Petición de Handshake en el cliente</h3> + +<p>A pesar de que estamos creando un servidor, un cliente es quien tiene que comenzar el proceso de Handshake de WebSocket. Entonces tú tienes que saber cómo interpretar la petición del cliente. El cliente enviará una linda petición HTTP estandar que lucirá algo asi (la versión del HTTP debe ser 1.1 o mayor y el método debe ser GET):</p> + +<pre>GET /chat HTTP/1.1 +Host: example.com:8000 +<strong>Upgrade: websocket</strong> +<strong>Connection: Upgrade</strong> +Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== +Sec-WebSocket-Version: 13 + +</pre> + +<p>El cliente puede solicitar aquí extensiones y/o sub protocolos; vea <a href="#Miscellaneous">Misceláneos</a> para más detalles. También, cabeceras comunes como <code>User-Agent</code>, <code>Referer</code>, <code>Cookie</code>, or cabeceras de autenticación podrían ser incluidos. Haz lo que quieras con ellos; no pertencen a WebSocket. También puedes ignorarlos. En muchas configuraciones comunes, un proxy inverso ya ha tratado con ellos.</p> + +<p>Si alguna cabecera no se entiende o posee un valor incorrecto, el servidor debe responder "<a href="https://developer.mozilla.org/es/docs/HTTP/Response_codes#400">400 Bad Request</a>" e inmediatamente cerrar la conexión. Normalmente, también puede dar la razón porque falló el <em>handshake</em> en el cuerpo de la respuesta HTTP, pero el mensaje podría no ser mostrado (el browser no lo muestra). Si el servidor no comprende que la versión del WebSockets, debería enviar una cabecera <code>Sec-WebSocket-Version</code> que contenga la(s) versión(es) no entendidas. (Esta guía explica v13, la más nueva). Ahora, vamos a ver la cabecera más curiosa, <code>Sec-WebSocket-Key</code>.</p> + +<div class="note"> +<p><strong>Tip:</strong> Todos los <strong>navegadores</strong> deben enviar una <a href="https://developer.mozilla.org/es/docs/HTTP/Access_control_CORS#Origin"><code>cabecera Origin</code></a>. Tu puedes usar esta cabecera por seguridad (revisando por el mismo origen, listas blancas/ listas negras, etc.) y enviar un <a href="https://developer.mozilla.org/es/docs/HTTP/Response_codes#403">403 Forbidden</a> si no te gusta lo que ves. Sin embargo, se advierte que los agentes no navegadores pueden enviar un falso <code>Origin</code>. La mayoría de las aplicaciones rechazaran las solicitudes sin esta cabecera.</p> +</div> + +<div class="note"> +<p><strong>Tip:</strong> The request-uri (<code>/chat</code> here) has no defined meaning in the spec. So many people cleverly use it to let one server handle multiple WebSocket applications. For example, <code>example.com/chat</code> could invoke a multiuser chat app, while <code>/game</code> on the same server might invoke a multiplayer game.</p> +</div> + +<div class="note"> +<p><strong>Note:</strong> <a href="https://developer.mozilla.org/en-US/docs/HTTP/Response_codes">Regular HTTP status codes</a> can only be used before the handshake. After the handshake succeeds, you have to use a different set of codes (defined in section 7.4 of the spec).</p> +</div> + +<h3 id="Respuesta_de_Handshake_del_servidor">Respuesta de Handshake del servidor</h3> + +<p>Después de la petición, el servidor debería enviar una linda respuesta (aunque todavía en formato HTTP) que se verá asi (hay que recordar que la cabecera termina con \r \n y agrega un \r \n extra después del último):</p> + +<pre><strong>HTTP/1.1 101 Switching Protocols</strong> +Upgrade: websocket +Connection: Upgrade +<strong>Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= + +</strong></pre> + +<p>Adicionalmente, el servidor puede decidir respecto de las solicitudes "extension/subprotocol" en este punto (ver <a href="#Miscellaneous">Miscelláneos</a> para más detalles). La cabecera <code>Sec-WebSocket-Accept</code> es interesante. El servidor debe derivarla a partir de la cabecera <code>Sec-WebSocket-Key</code> enviada anteriormente por el cliente. Para lograr esto se deben concatenar la cabecera del cliente<span style="line-height: 1.5em;"> </span><code style="font-size: 14px;">Sec-WebSocket-Key</code><span style="line-height: 1.5em;"> y el string "</span><code style="font-size: 14px;">258EAFA5-E914-47DA-95CA-C5AB0DC85B11</code><span style="line-height: 1.5em;">" (es un "</span><a href="https://en.wikipedia.org/wiki/Magic_string" style="line-height: 1.5em;">magic string</a><span style="line-height: 1.5em;">"), calcular el </span><a href="https://en.wikipedia.org/wiki/SHA-1" style="line-height: 1.5em;">hash SHA-1</a><span style="line-height: 1.5em;"> del resultado y devolver el string codificado en</span><span style="line-height: 1.5em;"> </span><a href="https://en.wikipedia.org/wiki/Base64" style="line-height: 1.5em;">base64</a><span style="line-height: 1.5em;"> de este hash.</span></p> + +<div class="note"> +<p><strong>FYI:</strong> Este aparentemente complicado e innecesario proceso se realiza de manera que sea obvio para el cliente si el servidor soporta o noWebSockets. Esto es importante de realizar, ya que podrían crearse problemas de seguridad si el servidor acepta conexiones WebSockets pero interpreta los datos como solicitudes HTTP.</p> +</div> + +<p>Así, si la cabecera <code>Sec-WebSocket-Key</code> era "<code>dGhlIHNhbXBsZSBub25jZQ==</code>", la correspondiente respuesta <code>Sec-WebSocket-Accept</code> será "<code>s3pPLMBiTxaQ9kYGzzhZRbK+xOo=</code>". Una vez que el servidor envía estas cabeceras, el "handshake" se considera completo y puedes comenzar a intercambiar datos.</p> + +<div class="note"> +<p>El servidor puede enviar otras cabeceras como Set-Cookie, o solicitar autenticación o redirigir mediante otros status codes antes de responder al handshake.</p> +</div> + +<h3 id="Llevando_registro_de_los_clientes">Llevando registro de los clientes</h3> + +<p>Esto no está directamente relacionado con el protocolo WebSocket, pero no está de más mencionarlo: tu servidor debe llevar el registro de los sockets de los clientes, de manera de no realizar handshakes constantemente con los clientes que ya han completado este proceso. La misma dirección IP cliente puede intentar conectarse múltiples veces (pero el servidor puede denegar la conexión si se intentan demasiadas conexiones con el objetivo de evitar ataques <a href="https://en.wikipedia.org/wiki/Denial_of_service">ataques DoS</a>).</p> + +<h2 id="Paso_2_Intercambiando_Data_Frames">Paso 2: Intercambiando Data Frames</h2> + +<p>Tanto el cliente como el servidor puede decidir enviar un mensaje en cualquier momento — ese es el encanto de los WebSockets. Sin embargo, extraer información de esos denominados "frames" o tramas de datos no es una experiencia muy mágica. Aunque todos los frames siguen el mismo formato específico, los datos que van del cliente al servidor se enmascaran utilizando el <a href="https://en.wikipedia.org/wiki/XOR_cipher">cifrado XOR</a> (con una clave de 32 bits). La sección 5 de la especificación describe esto en detalle.</p> + +<h3 id="Formato">Formato</h3> + +<p>Cada trama de datos (desde el cliente al servidor o viceversa) sigue este mismo formato:</p> + +<pre style="float: left; margin-right: 20px;"> 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-------+-+-------------+-------------------------------+ +|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| | | ++-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + +| Extended payload length continued, if payload len == 127 | ++ - - - - - - - - - - - - - - - +-------------------------------+ +| |Masking-key, if MASK set to 1 | ++-------------------------------+-------------------------------+ +| Masking-key (continued) | Payload Data | ++-------------------------------- - - - - - - - - - - - - - - - + +: Payload Data continued ... : ++ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +| Payload Data continued ... | ++---------------------------------------------------------------+</pre> + +<p>Los RSV1-3 se pueden ignorar, son para las extensiones.</p> + +<p>El bit MASK simplemente indica si el mensaje está codificado. Los mensajes del cliente deben estar enmascarados, por lo que tu servidor debe esperar que valga 1. (De hecho, la <a href="http://tools.ietf.org/html/rfc6455#section-5.1">sección 5.1 de las espeficicaciones</a> dice que tu servidor debe desconectarse de un cliente si ese cliente envía un mensaje sin enmascarar). Cuando se envía una trama al cliente, no lo ocultes y no pongas el bit de la máscara. Te explicaremos el enmascaramiento más tarde. <em>Nota: Tienes que enmascarar los mensajes incluso cuando uses un socket seguro.</em></p> + +<p>El campo opcode define cómo interpretar los datos de la carga útil:<code style="font-style: normal; line-height: 1.5;">0x0</code><span style="line-height: 1.5;"> </span><span style="line-height: 1.5;">para continuar,</span><span style="font-family: courier new,andale mono,monospace; line-height: 1.5;"> </span><code style="font-style: normal; line-height: 1.5;">0x1</code><span style="line-height: 1.5;"> para texto (que siempre se codifica con UTF-8), </span><code style="font-style: normal; line-height: 1.5;">0x2</code><span style="line-height: 1.5;"> para datos binarios, otros llamados "códigos de control" se explican más tarde. En esta versión de WebSockets, de <code>0x3</code> a <code>0x7</code> y de <code>0xB</code> a <code>0xF</code> no tienen significado.</span></p> + +<p>El bit FIN indica si este es el último mensaje de una serie. Si es 0, el servidor seguirá escuchando más partes del mensaje; de lo contrario, el servidor debería considerar el mensaje entregado. Más sobre esto después.</p> + +<h3 id="Decoding_Payload_Length">Decoding Payload Length</h3> + +<p>To read the payload data, you must know when to stop reading. That's why the payload length is important to know. Unfortunately, this is somewhat complicated. To read it, follow these steps:</p> + +<ol> + <li>Read bits 9-15 (inclusive) and interpret that as an unsigned integer. If it's 125 or less, then that's the length; you're <strong>done</strong>. If it's 126, go to step 2. If it's 127, go to step 3.</li> + <li>Read the next 16 bits and interpret those as an unsigned integer. You're <strong>done</strong>.</li> + <li>Read the next 64 bits and interpret those as an unsigned integer. You're <strong>done</strong>.</li> +</ol> + +<h3 id="Reading_and_Unmasking_the_Data">Reading and Unmasking the Data</h3> + +<p>If the MASK bit was set (and it should be, for client-to-server messages), read the next 4 octets (32 bits); this is the masking key. <span style="line-height: 1.5;">Once the payload length and masking key is decoded, you can go ahead and read that number of bytes from the socket. Let's call the data <strong>ENCODED</strong>, and the key <strong>MASK</strong>. To get <strong>DECODED</strong>, loop through the octets (bytes a.k.a. characters for text data) of <strong>ENCODED</strong> and XOR the octet with the (i modulo 4)th octet of MASK. In pseudo-code (that happens to be valid JavaScript):</span></p> + +<pre>var DECODED = ""; +for (var i = 0; i < ENCODED.length; i++) { + DECODED[i] = ENCODED[i] ^ MASK[i % 4]; +<span style="line-height: 1.5;">}</span></pre> + +<p><span style="line-height: 1.5;">Now you can figure out what <strong>DECODED</strong> means depending on your application.</span></p> + +<h3 id="Message_Fragmentation">Message Fragmentation</h3> + +<p>The FIN and opcode fields work together to send a message split up into separate frames. This is called message fragmentation. Fragmentation is only available on opcodes <code>0x0</code> to <code>0x2</code>.</p> + +<p><span style="line-height: 1.5;">Recall that the opcode tells what a frame is meant to do. If it's <code>0x1</code>, the payload is text. If it's <code>0x2</code>, the payload is binary data.</span><span style="line-height: 1.5;"> However, if it's </span><code style="font-style: normal; line-height: 1.5;">0x0,</code><span style="line-height: 1.5;"> the frame is a continuation frame. This means the server should concatenate the frame's payload to the last frame it received from that client.</span><span style="line-height: 1.5;"> Here is a rough sketch, in which a server reacts to a client sending text messages. The first message is sent in a single frame, while the second message is sent across three frames. FIN and opcode details are shown only for the client:</span></p> + +<pre style="font-size: 14px;"><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> + +<p>Notice the first frame contains an entire message (has <code>FIN=1</code> and <code>opcode!=0x0</code>), so the server can process or respond as it sees fit. The second frame sent by the client has a text payload (<code>opcode=0x1</code>), but the entire message has not arrived yet (<code>FIN=0</code>). All remaining parts of that message are sent with continuation frames (<code>opcode=0x0</code>), and the final frame of the message is marked by <code>FIN=1</code>. <a href="http://tools.ietf.org/html/rfc6455#section-5.4">Section 5.4 of the spec</a> describes message fragmentation.</p> + +<h2 id="Pings_and_Pongs_The_Heartbeat_of_WebSockets">Pings and Pongs: The Heartbeat of WebSockets</h2> + +<p>At any point after the handshake, either the client or the server can choose to send a ping to the other party. When the ping is received, the recipient must send back a pong as soon as possible. You can use this to make sure that the client is still connected, for example.</p> + +<p>A ping or pong is just a regular frame, but it's a <strong>control frame</strong>. Pings have an opcode of <code>0x9</code>, and pongs have an opcode of <code>0xA</code>. When you get a ping, send back a pong with the exact same Payload Data as the ping (for pings and pongs, the max payload length is 125). You might also get a pong without ever sending a ping; ignore this if it happens.</p> + +<div class="note"> +<p>If you have gotten more than one ping before you get the chance to send a pong, you only send one pong.</p> +</div> + +<h2 id="Step_4_Closing_the_connection">Step 4: Closing the connection</h2> + +<p>To close a connection either the client or server can send a control frame with data containing a specified control sequence to begin the closing handshake (detailed in <a href="http://tools.ietf.org/html/rfc6455#section-5.5.1">Section 5.5.1</a>). Upon receiving such a frame, the other peer sends a Close frame in response. The first peer then closes the connection. Any further data received after closing of connection is then discarded. </p> + +<h2 id="Miscellaneous_2"><a name="Miscellaneous">Miscellaneous</a></h2> + +<div class="note"> +<p>WebSocket codes, extensions, subprotocols, etc. are registered at the <a href="http://www.iana.org/assignments/websocket/websocket.xml">IANA WebSocket Protocol Registry</a>.</p> +</div> + +<p>WebSocket extensions and subprotocols are negotiated via headers during <a href="#Handshake">the handshake</a>. Sometimes extensions and subprotocols seem too similar to be different things, but there is a clear distinction. Extensions control the WebSocket <strong>frame</strong> and <strong>modify</strong> the payload, while subprotocols structure the WebSocket <strong>payload</strong> and <strong>never modify</strong> anything. Extensions are optional and generalized (like compression); subprotocols are mandatory and localized (like ones for chat and for MMORPG games).</p> + +<h3 id="Extensions">Extensions</h3> + +<div class="note"> +<p><strong>This section needs expansion. Please edit if you are equipped to do so.</strong></p> +</div> + +<p>Think of an extension as compressing a file before e-mailing it to someone. Whatever you do, you're sending the <em>same</em> data in different forms. The recipient will eventually be able to get the same data as your local copy, but it is sent differently. That's what an extension does. WebSockets defines a protocol and a simple way to send data, but an extension such as compression could allow sending the same data but in a shorter format.</p> + +<div class="note"> +<p>Extensions are explained in sections 5.8, 9, 11.3.2, and 11.4 of the spec.</p> +</div> + +<p><em>TODO</em></p> + +<h3 id="Subprotocols">Subprotocols</h3> + +<p>Think of a subprotocol as a custom <a href="https://en.wikipedia.org/wiki/XML_schema">XML schema</a> or <a href="https://en.wikipedia.org/wiki/Document_Type_Definition">doctype declaration</a>. You're still using XML and its syntax, but you're additionally restricted by a structure you agreed on. WebSocket subprotocols are just like that. They do not introduce anything fancy, they just establish structure. Like a doctype or schema, both parties must agree on the subprotocol; unlike a doctype or schema, the subprotocol is implemented on the server and cannot be externally refered to by the client.</p> + +<div class="note"> +<p>Subprotocols are explained in sections 1.9, 4.2, 11.3.4, and 11.5 of the spec.</p> +</div> + +<p>A client has to ask for a specific subprotocol. To do so, it will send something like this <strong>as part of the original handshake</strong>:</p> + +<pre>GET /chat HTTP/1.1 +... +Sec-WebSocket-Protocol: soap, wamp + +</pre> + +<p>or, equivalently:</p> + +<pre>... +Sec-WebSocket-Protocol: soap +Sec-WebSocket-Protocol: wamp + +</pre> + +<p>Now the server must pick one of the protocols that the client suggested and it supports. If there are more than one, send the first one the client sent. Imagine our server can use both <code>soap</code> and <code>wamp</code>. Then, in the response handshake, it'll send:</p> + +<pre>Sec-WebSocket-Protocol: soap + +</pre> + +<div class="warning"> +<p>The server can't send more than one <code>Sec-Websocket-Protocol</code> header.<br> + <span style="line-height: 1.5;">If the server doesn't want to use a</span><span style="line-height: 1.5;">ny subprotocol, </span><strong style="line-height: 1.5;">it shouldn't send any <code>Sec-WebSocket-Protocol</code> header</strong><span style="line-height: 1.5;">. Sending a blank header is incorrect.<br> + The client may close the connection if it doesn't get the subprotocol it wants.</span></p> +</div> + +<p>If you want your server to obey certain subprotocols, then naturally you'll need extra code on the server. Let's imagine we're using a subprotocol <code>json</code>. In this subprotocol, all data is passed as <a href="https://en.wikipedia.org/wiki/JSON">JSON</a>. If the client solicits this protocol and the server wants to use it, the server will need to have a JSON parser. Practically speaking, this will be part of a library, but the server will need to pass the data around.</p> + +<div class="note"> +<p><strong>Tip:</strong> To avoid name conflict, it's recommended to make your subprotocol name part of a domain string. If you are building a custom chat app that uses a proprietary format exclusive to Example Inc., then you might use this: <code>Sec-WebSocket-Protocol: chat.example.com</code>. For different versions, a widely-used method is to add a <code>/</code> followed by the version number, like <code>chat.example.com/2.0</code>. Note that this isn't required, it's just an optional convention, and you can use any string you wish.</p> +</div> + +<h2 id="Related">Related</h2> + +<ul> + <li><a href="/en-US/docs/WebSockets/Writing_WebSocket_server" title="/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> diff --git a/files/es/web/api/websockets_api/index.html b/files/es/web/api/websockets_api/index.html new file mode 100644 index 0000000000..e1c339558f --- /dev/null +++ b/files/es/web/api/websockets_api/index.html @@ -0,0 +1,172 @@ +--- +title: WebSockets +slug: Web/API/WebSockets_API +translation_of: Web/API/WebSockets_API +--- +<p>{{DefaultAPISidebar("Websockets API")}}</p> + +<p><strong>WebSockets </strong>es una tecnología avanzada que hace posible abrir una sesión de comunicación interactiva entre el navegador del usuario y un servidor. Con esta API, puede enviar mensajes a un servidor y recibir respuestas controladas por eventos sin tener que consultar al servidor para una respuesta.</p> + +<h2 id="Interfaces">Interfaces</h2> + +<dl> + <dt><a href="/en-US/docs/Web/API/WebSocket" title="en/WebSockets/WebSockets reference/WebSocket"><code>WebSocket</code></a></dt> + <dd>El interfaz principal para conectar a un servidor Websocket y así enviar y recibir datos a través de la conexión.</dd> + <dt><code><a href="/en-US/docs/Web/API/CloseEvent" title="en/WebSockets/WebSockets reference/CloseEvent">CloseEvent</a></code></dt> + <dd>El evento enviado por el objeto WebSocket cuando se cierra la conexión.</dd> + <dt><a href="/en-US/docs/Web/API/MessageEvent" title="en/WebSockets/WebSockets reference/MessageEvent"><code>MessageEvent</code></a></dt> + <dd>El evento enviado por el objeto WebSocket cuando se recibe un mensaje enviado desde el servidor.</dd> +</dl> + +<div class="section"> +<h2 class="Tools" id="Tools" name="Tools">Herramientas</h2> + +<ul> + <li><a class="external" href="http://socket.io" title="http://socket.io/">Socket.IO</a>: Una poderosa API WebSocket multi-plataforma para <a class="external" href="http://nodejs.org" title="http://nodejs.org/">Node.js</a>.</li> + <li><a class="link-https" href="https://github.com/Worlize/WebSocket-Node" title="https://github.com/Worlize/WebSocket-Node">WebSocket-Node</a>: Un servidor WebSocket API implementado para <a class="external" href="http://nodejs.org" title="http://nodejs.org/">Node.js</a>.</li> + <li><a href="http://www.totaljs.com">Total.js</a>: Framework para aplicaciones web para <a href="http://www.nodejs.org">Node.js</a> (Ejemplo: <a href="https://github.com/totaljs/examples/tree/master/websocket">WebSocket chat</a>)</li> + <li><a href="https://www.npmjs.com/package/faye-websocket">Faye</a>: Un servidor y cliente <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API">WebSocket</a> (conexión bidireccional) y <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventSource/">EventSource</a> (conexión unidireccional) para <a class="external" href="http://nodejs.org" title="http://nodejs.org/">Node.js</a>.</li> +</ul> + +<h2 class="Related_Topics" id="Related_Topics" name="Related_Topics">Temas RELACIONADOS</h2> + +<ul> + <li><a href="/en-US/docs/AJAX" title="AJAX">AJAX</a>, <a href="/en-US/docs/JavaScript" title="JavaScript">JavaScript</a></li> +</ul> +</div> + +<h2 id="Ver_también">Ver también</h2> + +<ul> + <li><a class="external" href="http://tools.ietf.org/html/rfc6455">RFC 6455 - The WebSocket Protocol</a></li> + <li><a class="external" href="http://www.w3.org/TR/websockets/">WebSocket API Specification</a></li> + <li><a href="/en-US/docs/Server-sent_events" title="Server-sent_events">Server-Sent Events</a></li> +</ul> + +<h2 id="Compatibilidad_con_navegadores">Compatibilidad con navegadores</h2> + +<p>{{CompatibilityTable}}</p> + +<div id="compat-desktop"> +<table class="compat-table"> + <tbody> + <tr> + <th>Característica</th> + <th>Chrome</th> + <th>Firefox (Gecko)</th> + <th>Internet Explorer</th> + <th>Opera</th> + <th>Safari</th> + </tr> + <tr> + <td>Versión -76 {{obsolete_inline}}</td> + <td>6</td> + <td>{{CompatGeckoDesktop("2.0")}}</td> + <td>{{CompatNo}}</td> + <td>11.00 (disabled)</td> + <td>5.0.1</td> + </tr> + <tr> + <td>Protocolo versión 7</td> + <td>{{CompatNo}}</td> + <td>{{CompatGeckoDesktop("6.0")}}<br> + {{property_prefix("Moz")}}</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + </tr> + <tr> + <td>Protocolo versión 10</td> + <td>14</td> + <td>{{CompatGeckoDesktop("7.0")}}<br> + {{property_prefix("Moz")}}</td> + <td>HTML5 Labs</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + </tr> + <tr> + <td>RFC 6455 (IETF Draft 17)</td> + <td>16</td> + <td>{{CompatGeckoDesktop("11.0")}}</td> + <td>10</td> + <td>12.10</td> + <td>{{CompatUnknown}}</td> + </tr> + </tbody> +</table> +</div> + +<div id="compat-mobile"> +<table class="compat-table"> + <tbody> + <tr> + <th>Característica</th> + <th>Android</th> + <th>Firefox Mobile (Gecko)</th> + <th>IE Mobile</th> + <th>Opera Mobile</th> + <th>Safari Mobile</th> + </tr> + <tr> + <td>Versión -76 {{obsolete_inline}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + </tr> + <tr> + <td>Protocolo versión 7</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + </tr> + <tr> + <td>Protocolo versión 8 (IETF draft 10)</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatGeckoMobile("7.0")}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + <td>{{CompatUnknown}}</td> + </tr> + <tr> + <td>RFC 6455 (IETF Draft 17)</td> + <td>16</td> + <td>{{CompatGeckoDesktop("11.0")}}</td> + <td>{{CompatUnknown}}</td> + <td>12.10</td> + <td>{{CompatUnknown}}</td> + </tr> + </tbody> +</table> +</div> + +<h3 id="Notas_para_Gecko">Notas para Gecko</h3> + +<p>La compatibilidad de Firefox con WebSockets ha seguido la evolución de la especificación WebSocket. Firefox 6 implementa la versión 7 del protocolo subyacente, mientras que Firefox 7 implementa la versión 8 (como especifica IETF draft 10). Firefox mobile tuvo compatibilidad con WebSocket en Firefox mobile 7.0.</p> + +<h4 id="Gecko_6.0">Gecko 6.0</h4> + +<p>Prior to Gecko 6.0 {{geckoRelease("6.0")}}, there was, incorrectly, a <code>WebSocket</code> object that some sites were thinking implied that <code>WebSocket</code> services were not prefixed; this object has been renamed to <code>MozWebSocket</code>.</p> + +<h4 id="Gecko_7.0">Gecko 7.0</h4> + +<p>Starting in Gecko 7.0 {{geckoRelease("7.0")}}, the <code>network.websocket.max-connections</code> preference is used to determine the maximum number of WebSocket connections that can be open at a time. The default value is 200.</p> + +<h4 id="Gecko_8.0">Gecko 8.0</h4> + +<p>Starting in Gecko 8.0 {{geckoRelease("8.0")}}, the deflate-stream extension to the WebSocket protocol has been disabled, since it's been deprecated from the specification drafts. This resolves incompatibilities with some sites.</p> + +<h4 id="Gecko_11.0">Gecko 11.0</h4> + +<p>Prior to Gecko 11.0, both incoming and outgoing messages were limited to 16 MB in size. They may now be up to 2 GB in size. Note, however, that memory limitations (especially on mobile devices) make that a theoretical maximum, not a practical one. In reality, transfers of that size will fail on devices that don't have enough memory.</p> + +<p>Additionally, ArrayBuffer send and receive support for binary data has been implemented.</p> + +<p>Starting in Gecko 11.0, the WebSocket API is no longer prefixed.</p> + +<div class="warning"><strong>Warning:</strong> Among other things, a key reason WebSockets was disabled by default in Firefox 4 and 5 is the discovery of a <a class="external" href="http://www.ietf.org/mail-archive/web/hybi/current/msg04744.html" title="http://www.ietf.org/mail-archive/web/hybi/current/msg04744.html">security issue in the protocol's design</a>. This was fixed in Firefox 6 by implementing a newer version of the protocol that corrects the problem.</div> + +<div>{{HTML5ArticleTOC}}</div> diff --git a/files/es/web/api/websockets_api/writing_websocket_client_applications/index.html b/files/es/web/api/websockets_api/writing_websocket_client_applications/index.html new file mode 100644 index 0000000000..3dda33b8da --- /dev/null +++ b/files/es/web/api/websockets_api/writing_websocket_client_applications/index.html @@ -0,0 +1,197 @@ +--- +title: Escribiendo aplicaciones con WebSockets +slug: Web/API/WebSockets_API/Writing_WebSocket_client_applications +tags: + - Guía WebSocket WebSockets +translation_of: Web/API/WebSockets_API/Writing_WebSocket_client_applications +--- +<p>{{ draft() }}</p> + +<p><span style="background-clip: initial; font-family: arial,sans-serif; font-size: 10.5pt; line-height: 115%;">WebSockets es una tecnología basada en el protocolo ws, este hace posible establecer una conexión continua full-duplex, entre un cliente y servidor. Un cliente websocket podría ser el navegador del usuario, pero el protocolo es una plataforma independiente.</span></p> + +<div class="note"><strong>Nota:</strong> Tenemos un ejemplo funcional de un sistema de chat/servidor usado para ejemplos de código que estará disponible una vez nuestra infraestructura esté en posición de hospedar ejemplos de WebSocket apropiadamente.</div> + +<h2 id="Disponibilidad_de_WebSockets">Disponibilidad de WebSockets</h2> + +<p>La API de WebSocket esta disponible para el código JavaScript cuyo alcance DOM sea un objeto {{ domxref("Window") }} o cualquier objeto implementando {{ domxref("WorkerUtils") }}; si es así, puedes usarlos desde los Web Workers.</p> + +<div class="note"><strong>Nota: </strong>La API de WebSockets (y el protocolo subyacente) continúan en activo desarrollo, y existen muchos problemas de compatibilidad entre los navegadores en este momento (e inclusive entre los diferentes lanzamientos del mismo navegador).</div> + +<h2 id="Creando_un_Objeto_WebSocket">Creando un Objeto WebSocket</h2> + +<p>Para comunicarse utilizando el protocolo webSocket, necesitarás crear un objeto WebSocket; este automáticamente abrirá una conexión temporal al servidor.</p> + +<p>El constructor WebSocket requiere de un parámetro obligatorio y otro opcional:</p> + +<pre>WebSocket WebSocket( + in DOMString url, + in optional DOMString protocols +); + +WebSocket WebSocket( + in DOMString url, + in optional DOMString[] protocols +); +</pre> + +<dl> + <dt><code>url</code></dt> + <dd>La url a la que conectar; esta es la URL a la que el WebSocket responde.</dd> + <dt><code>protocols</code> {{ optional_inline() }}</dt> + <dd>Un string o array de strings con el/los protocolos a usar. Estos strings son usados para indicar sub-protocolos, para que el servidor pueda implementar multiples sub-protocolos WebSocket (por ejemplo, puede necesitar usar un servidor para manejar diferentes tipos de interacciones dependiendo del protocolo especificado). Si no se especifica el string como protocolo, se asumirá un string vacío.</dd> +</dl> + +<p>El constructor puede lanzar excepciones:</p> + +<dl> + <dt><code>SECURITY_ERR</code></dt> + <dd>El puerto de la conexión está siendo bloqueado.</dd> +</dl> + +<dl> +</dl> + +<h3 id="Errores_de_conexión">Errores de conexión</h3> + +<p>Si ocurre un error al intentar conectar, lo primero que recibiremos será un evento con el nombre de "error" en el objeto <code><a href="/en/WebSockets/WebSockets_reference/WebSocket" title="WebSocket">WebSocket</a> </code>(de este modo se invoca el manejador <code>onerror</code>), y luego <a href="/en/WebSockets/WebSockets_reference/CloseEvent" title="CloseEvent"><code>CloseEvent</code></a> es enviado al objeto <code><a href="/en/WebSockets/WebSockets_reference/WebSocket" title="WebSocket">WebSocket</a> </code>(de este modo se invoca el manejador <code>onclose</code>), para indicar la razón del cierre de la conexión.</p> + +<p>A partir de Firefox 11, es normal recibir un mensaje de error descriptivo en la consola de la plataforma Mozilla, y un código de cierre como está definido en el <a class="external" href="http://tools.ietf.org/html/rfc6455#section-7.4" title="RFC 6455 Section 7.4">RFC 6455, Section 7.4</a> a través de un <a href="/en/WebSockets/WebSockets_reference/CloseEvent" title="CloseEvent"><code>CloseEvent</code></a>.</p> + +<h3 id="Ejemplos">Ejemplos</h3> + +<p>En este ejemplo de crea un nuevo WebSocket, conectandose al servidor <code><span class="nowiki">ws://www.example.com/socketserver</span></code>. El nombre del protocolo "protocolOne" es el utilizado para la consulta del socket, aunque puede ser omitido.</p> + +<pre class="brush: js">var exampleSocket = new WebSocket("ws://www.example.com/socketserver", "protocolOne"); +</pre> + +<p>Como respuesta, <code>exampleSocket</code>.<code>readyState</code> es <code>CONNECTING</code>. El <code>readyState</code> será <code>OPEN</code> una vez que la conexión este lista para transferir información.</p> + +<p>Si se quiere establecer una conexión que soporte varios protocolos, se puede establecer un array de protocolos:</p> + +<pre class="brush: js">var exampleSocket = new WebSocket("ws://www.example.com/socketserver", ["protocolOne", "protocolTwo"]); +</pre> + +<p>Una vez que la conexión este establecida (<code>readyState</code> estará <code>OPEN</code>), <code>exampleSocket.protocol</code> te dirá qué protocolo ha seleccionado el servidor.</p> + +<p>En los ejemplos anteriores <code>ws</code> sustituye <code>http</code>, y de igual manera <code>wss</code> sustituye a <code>https</code>. Al crear un WebSocket se hace uso del mecanismo Upgrade de HTTP, por lo que la petición de actualización del protocolo está implícita cuando accedemos al servidor HTTP con <code><span class="nowiki">ws://www.example.com</span></code> o <code><span class="nowiki">wss://www.example.com</span></code>.</p> + +<h2 id="Enviando_Información_al_servidor">Enviando Información al servidor</h2> + +<p>Una vez la conexión esta abierta, se puede comenzar<span style="line-height: 1.5;"> a enviar datos al servidor. Para hacer esto, simplemente se llama al metodo</span><span style="line-height: 1.5;"> </span><a href="/en/WebSockets/WebSockets_reference/WebSocket#send()" style="line-height: 1.5;" title="en/WebSockets/WebSockets reference/WebSocket#send()"><code>send()</code></a><span style="line-height: 1.5;"> del objeto </span><code style="font-style: normal; line-height: 1.5;">WebSocket</code>, <span style="line-height: 1.5;">cada vez que se desea enviar un mensaje:</span></p> + +<pre class="brush: js">exampleSocket.send("Here's some text that the server is urgently awaiting!"); +</pre> + +<p>Puedes enviar información como un string, {{ domxref("Blob") }}, o en un <a href="/en/JavaScript_typed_arrays/ArrayBuffer" title="en/JavaScript typed arrays/ArrayBuffer"><code>ArrayBuffer</code></a>.</p> + +<div class="note"><strong>Nota:</strong> Antes de la version 11, Firefox sólo soportaba el envío de datos como una cadena.</div> + +<p>Como la conexión es asincronica y es propensa a fallar, no hay garantia de poder llamar al metodo <code>send()</code> inmediatamente despúes de haber creado el objeto WebSocket de manera exitosa. Para enviar información se debe estar seguro de que almenos una conexión ya esta abierta, usando el manejador <code>onopen</code>:</p> + +<pre class="brush: js">exampleSocket.onopen = function (event) { + exampleSocket.send("Here's some text that the server is urgently awaiting!"); +}; +</pre> + +<h3 id="Usando_JSON_para_transferir_Objetos">Usando JSON para transferir Objetos</h3> + +<p>Una forma de enviar información compleja al servidor es utilizar <a href="/en/JSON" title="en/JSON">JSON</a>. Por ejemplo, un programa para chatear puede interactuar con el servidor usando un protocolo que implementa el uso de paquetes de JSON:</p> + +<pre class="brush: js">// Envia texto a todos los usuarios através del servidor +function sendText() { + // Se construye un Objeto msg que contiene la información que el servidor necesita procesar de ese cliente. + var msg = { + type: "message", + text: document.getElementById("text").value, + id: clientID, + date: Date.now() + }; + + // Send the msg object as a JSON-formatted string. + exampleSocket.send(JSON.stringify(msg)); + + // Blank the text input element, ready to receive the next line of text from the user. + document.getElementById("text").value = ""; +} +</pre> + +<h2 id="Recibiendo_mensajes_del_servidor">Recibiendo mensajes del servidor</h2> + +<p>WebSockets<span style="line-height: 1.5;"> </span><span style="line-height: 1.5;">API</span><span style="line-height: 1.5;"> es un manejador de eventos; cuando el mensaje es recibido, un "message" el evento es pasado el manejador </span><code style="font-style: normal; line-height: 1.5;">onmessage</code><span style="line-height: 1.5;">. Para escuchar la entrada de información, se puede hacer algo como lo siguiente:</span></p> + +<pre class="brush: js">exampleSocket.onmessage = function (event) { + console.log(event.data); +} +</pre> + +<h3 id="Recibiendo_e_interpretando_objetos_JSON">Recibiendo e interpretando objetos JSON</h3> + +<p>Vamos a imaginar una aplicación de chat, donde el cliente usa JSON para transmitir objetos con información. Hay varios tipos de paquetes que el cliente recibirá:</p> + +<ul> + <li>Inicio de sesión handshake</li> + <li>Mensajes de texto</li> + <li>Actualización de Lista de usuarios</li> +</ul> + +<p>El código que interpretará los mensajes entrantes será así:</p> + +<pre class="brush: js">exampleSocket.onmessage = function(event) { + var f = document.getElementById("chatbox").contentDocument; + var text = ""; + var msg = JSON.parse(event.data); + var time = new Date(msg.date); + var timeStr = time.toLocaleTimeString(); + + switch(msg.type) { + case "id": + clientID = msg.id; + setUsername(); + break; + case "username": + 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>"; + 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>" + break; + case "userlist": + var ul = ""; + for (i=0; i < msg.users.length; i++) { + ul += msg.users[i] + "<br>"; + } + document.getElementById("userlistbox").innerHTML = ul; + break; + } + + if (text.length) { + f.write(text); + document.getElementById("chatbox").contentWindow.scrollByPages(1); + } +}; +</pre> + +<p>Se usa <code><a href="/en/JavaScript/Reference/Global_Objects/JSON/parse" title="en/JavaScript/Reference/Global Objects/JSON/parse">JSON.parse()</a></code> para convertir el objeto JSON de vuelta al original, luego se examina y se realiza la acción pertinente.</p> + +<h3 id="Formato_de_texto_de_los_datos">Formato de texto de los datos</h3> + +<p>El texto recibido a través de la conexión WebSocket está en formato UTF-8.</p> + +<p>Antes de Gecko 9.0 {{ geckoRelease("9.0") }}, algunos no-caracteres que siguen siendo texto UTF-8 válido podrían causar el cierre de la conexión. Ahora Gecko permite esos valores.</p> + +<h2 id="Cerrando_la_conexión">Cerrando la conexión</h2> + +<p>Cuando se ha terminado de usar la conexión WebSocket, se llama el método <code><a href="/en/WebSockets/WebSockets_reference/WebSocket#close()" title="en/WebSockets/WebSockets reference/WebSocket#close()">close()</a></code> del objeto <code>WebSocket</code>:</p> + +<pre class="brush: js">exampleSocket.close(); +</pre> + +<p>Puede ser de gran ayuda revisar el atributo <code>bufferedAmount</code> del socket para verificar que toda la información ha sido enviada antes de intentar cerrar el socket.</p> + +<h2 id="Consideraciones_de_Seguridad">Consideraciones de Seguridad</h2> + +<p>Los WebSockets no deben ser usados en entornos de contenido mixto; eso es, no debes abrir una conexión de WebSocket <em>no segura</em> desde una página cargada usando <em>HTTPS </em>o viceversa. De hecho, muchos navegadores solo admiten conexiones WebSocket seguras, y ya no soportan su uso en contextos no seguros.</p> + +<p>{{ languages ( {"zh-tw": "zh_tw/WebSockets/Writing_WebSocket_client_applications"} ) }}</p> |