From 1109132f09d75da9a28b649c7677bb6ce07c40c0 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:41:45 -0500 Subject: initial commit --- .../escribiendo_servidor_websocket/index.html | 244 ++++++++++++++++++++ .../index.html | 246 +++++++++++++++++++++ files/es/web/api/websockets_api/index.html | 172 ++++++++++++++ .../index.html | 197 +++++++++++++++++ 4 files changed, 859 insertions(+) create mode 100644 files/es/web/api/websockets_api/escribiendo_servidor_websocket/index.html create mode 100644 files/es/web/api/websockets_api/escribiendo_servidores_con_websocket/index.html create mode 100644 files/es/web/api/websockets_api/index.html create mode 100644 files/es/web/api/websockets_api/writing_websocket_client_applications/index.html (limited to 'files/es/web/api/websockets_api') 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 +--- +

Introducción

+ +

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.

+ +

Este servidor se ajusta a RFC 6455 por lo que solo manejará las conexiones de Chrome version 16, Firefox 11, IE 10 and superiores.

+ +

Primeros pasos

+ +

WebSocket se comunica a través de conexiones TCP (Transmission Control Protocol), afortunadamente C# tiene una clase TcpListener la cual hace lo que su nombre sugiere. Esta se encuentra en el namespace System.Net.Sockets.

+ +
+

Es una buena idea usar la instrucción using para escribir menos. Eso significa que no tendrás que re escribir el namespace de nuevo en cada ocasión.

+
+ +

TcpListener

+ +

Constructor:

+ +
TcpListener(System.Net.IPAddress localaddr, int port)
+ +

localaddr especifica la IP a escuchar y port especifica el puerto.

+ +
+

Para crear un objeto IPAddress desde un string, usa el método estático Parse de IPAddres.

+
+ +

Métodos:

+ + + +

Aquí está como utilizar lo que hemos aprendido:

+ +
​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.");
+    }
+}
+
+ +

TcpClient

+ +

Métodos:

+ + + +

Propiedades:

+ + + +

NetworkStream

+ +

Métodos:

+ +
Write(Byte[] buffer, int offset, int size)
+ +

Escribe bytes desde el buffer; el offset y el size determinan la longitud del mensaje.

+ +
Read(Byte[] buffer, int offset, int size)
+ +

Lee bytes al buffer; el offset y el size determinan la longitud del mensaje.

+ +

Ampliemos nuestro ejemplo anterior.

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

Handshaking

+ +

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 handshaking.

+ +

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.

+ +
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 {
+
+}
+ +

Esta respuesta es fácil de construir, pero puede ser un poco díficil de entender. La explicación completa del handshake al servidor puede encontrarse en  RFC 6455, section 4.2.2. Para nuestros propósitos, solo construiremos una respuesta simple.

+ +

Debes:

+ +
    +
  1. Obtener el valor de "Sec-WebSocket-Key" sin espacios iniciales ni finales de el encabezado de la solicitud
  2. +
  3. Concatenarlo con "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
  4. +
  5. Calcular el código SHA-1 y Base64
  6. +
  7. Escribe el valor Sec-WebSocket-Accept en el encabezado como parte de la respuesta HTTP.
  8. +
+ +
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);
+}
+
+ +

Decoding messages

+ +

Luego de un handshake exitoso el cliente puede enviar mensajes al servidor, pero estos serán codificados.

+ +

Si nosotros enviamos "MDN", obtendremos estos bytes:

+ + + + + + + + + + + + + + + +
129131618435611216109
+ +

- 129:

+ + + + + + + + + + + + + + + + + + + + +
FIN (¿Es el mensaje completo?)RSV1RSV2RSV3Opcode
10000x1=0001
+ +

FIN: Puedes enviar tu mensaje en marcos, pero ahora debe mantener las cosas simples.
+ Opcode 0x1 significa que es un texto. Lista completa de Opcodes

+ +

- 131:

+ +

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.

+ +
+

Puedo tomar 128, porque el primer bit siempre es 1.

+
+ +

- 61, 84, 35 y 6 son los bytes de la clave a decodificar. Cambian en cada oportunidad.

+ +

- Los bytes codificados restantes son el mensaje.

+ +

Algoritmo de decodificación

+ +

byte decodificado = byte codificado XOR (posición del byte codificado Mod 4) byte de la clave

+ +

Ejemplo en C#:

+ +
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]);
+}
+ +

Relacionado

+ + + +
 
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 +--- +

{{gecko_minversion_header("2")}}

+ +

Introducción

+ +

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.

+ +

Un servidor WebSocket puede ser escrito en cualquier lenguaje de programación Server-Side que sea soporte Berkeley Sockets, 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.
+
+ 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.

+ +
+

Lea las últimas especificaciones oficiales de WebSocket RFC 6455. 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.

+
+ +

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 Reverse Proxy (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.
+  

+ +

Paso 1: El Handshake del WebSocket

+ +

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.

+ +
+

Advertencia: 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). 

+
+ +

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.

+ +

Petición de Handshake en el cliente

+ +

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):

+ +
GET /chat HTTP/1.1
+Host: example.com:8000
+Upgrade: websocket
+Connection: Upgrade
+Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
+Sec-WebSocket-Version: 13
+
+
+ +

El cliente puede solicitar aquí extensiones y/o sub protocolos; vea Misceláneos para más detalles. También, cabeceras comunes como User-Agent, RefererCookie, 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.

+ +

Si alguna cabecera no se entiende o posee un valor incorrecto, el servidor debe responder "400 Bad Request" e inmediatamente cerrar la conexión. Normalmente, también puede dar la razón porque falló el handshake 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 Sec-WebSocket-Version 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, Sec-WebSocket-Key.

+ +
+

Tip: Todos los navegadores deben enviar una cabecera Origin. Tu puedes usar esta cabecera por seguridad (revisando por el mismo origen, listas blancas/ listas negras, etc.) y enviar un 403 Forbidden si no te gusta lo que ves. Sin embargo, se advierte que los agentes no navegadores pueden enviar un falso Origin.  La mayoría de las aplicaciones rechazaran las solicitudes sin esta cabecera.

+
+ +
+

Tip: The request-uri (/chat here) has no defined meaning in the spec. So many people cleverly use it to let one server handle multiple WebSocket applications. For example, example.com/chat could invoke a multiuser chat app, while /game on the same server might invoke a multiplayer game.

+
+ +
+

Note: Regular HTTP status codes 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).

+
+ +

Respuesta de Handshake del servidor

+ +

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):

+ +
HTTP/1.1 101 Switching Protocols
+Upgrade: websocket
+Connection: Upgrade
+Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
+
+
+ +

Adicionalmente, el servidor puede decidir respecto de las solicitudes "extension/subprotocol" en este punto (ver Miscelláneos para más detalles). La cabecera Sec-WebSocket-Accept es interesante. El servidor debe derivarla a partir de la cabecera Sec-WebSocket-Key enviada anteriormente por el cliente. Para lograr esto se deben concatenar la cabecera del cliente Sec-WebSocket-Key y el string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" (es un "magic string"), calcular el hash SHA-1 del resultado y devolver el string codificado en base64 de este hash.

+ +
+

FYI: 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.

+
+ +

Así, si la cabecera Sec-WebSocket-Key era "dGhlIHNhbXBsZSBub25jZQ==", la correspondiente respuesta Sec-WebSocket-Accept será "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=". Una vez que el servidor envía estas cabeceras, el "handshake" se considera completo y puedes comenzar a intercambiar datos.

+ +
+

El servidor puede enviar otras cabeceras como Set-Cookie, o solicitar autenticación o redirigir mediante otros status codes antes de responder al handshake.

+
+ +

Llevando registro de los clientes

+ +

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 ataques DoS).

+ +

Paso 2: Intercambiando Data Frames

+ +

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 cifrado XOR (con una clave de 32 bits). La sección 5 de la especificación describe esto en detalle.

+ +

Formato

+ +

Cada trama de datos (desde el cliente al servidor o viceversa) sigue este mismo formato:

+ +
 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 ...                |
++---------------------------------------------------------------+
+ +

Los RSV1-3 se pueden ignorar, son para las extensiones.

+ +

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 sección 5.1 de las espeficicaciones  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. Nota: Tienes que enmascarar los mensajes incluso cuando uses un socket seguro.

+ +

El campo opcode define cómo interpretar los datos de la carga útil:0x0 para continuar, 0x1 para texto (que siempre se codifica con UTF-8), 0x2 para datos binarios, otros llamados "códigos de control" se explican más tarde. En esta versión de WebSockets, de 0x3 a 0x7 y de 0xB a 0xF no tienen significado.

+ +

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.

+ +

Decoding Payload Length

+ +

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:

+ +
    +
  1. 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 done. If it's 126, go to step 2. If it's 127, go to step 3.
  2. +
  3. Read the next 16 bits and interpret those as an unsigned integer. You're done.
  4. +
  5. Read the next 64 bits and interpret those as an unsigned integer. You're done.
  6. +
+ +

Reading and Unmasking the Data

+ +

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. 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 ENCODED, and the key MASK. To get DECODED, loop through the octets (bytes a.k.a. characters for text data) of ENCODED and XOR the octet with the (i modulo 4)th octet of MASK. In pseudo-code (that happens to be valid JavaScript):

+ +
var DECODED = "";
+for (var i = 0; i < ENCODED.length; i++) {
+    DECODED[i] = ENCODED[i] ^ MASK[i % 4];
+}
+ +

Now you can figure out what DECODED means depending on your application.

+ +

Message Fragmentation

+ +

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 0x0 to 0x2.

+ +

Recall that the opcode tells what a frame is meant to do. If it's 0x1, the payload is text. If it's 0x2, the payload is binary data. However, if it's 0x0, 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. 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:

+ +
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!
+ +

Notice the first frame contains an entire message (has FIN=1 and opcode!=0x0), so the server can process or respond as it sees fit. The second frame sent by the client has a text payload (opcode=0x1), but the entire message has not arrived yet (FIN=0). All remaining parts of that message are sent with continuation frames (opcode=0x0), and the final frame of the message is marked by FIN=1. Section 5.4 of the spec describes message fragmentation.

+ +

Pings and Pongs: The Heartbeat of WebSockets

+ +

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.

+ +

A ping or pong is just a regular frame, but it's a control frame. Pings have an opcode of 0x9, and pongs have an opcode of 0xA. 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.

+ +
+

If you have gotten more than one ping before you get the chance to send a pong, you only send one pong.

+
+ +

Step 4: Closing the connection

+ +

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 Section 5.5.1). 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. 

+ +

Miscellaneous

+ +
+

WebSocket codes, extensions, subprotocols, etc. are registered at the IANA WebSocket Protocol Registry.

+
+ +

WebSocket extensions and subprotocols are negotiated via headers during the handshake. Sometimes extensions and subprotocols seem too similar to be different things, but there is a clear distinction. Extensions control the WebSocket frame and modify the payload, while subprotocols structure the WebSocket payload and never modify anything. Extensions are optional and generalized (like compression); subprotocols are mandatory and localized (like ones for chat and for MMORPG games).

+ +

Extensions

+ +
+

This section needs expansion. Please edit if you are equipped to do so.

+
+ +

Think of an extension as compressing a file before e-mailing it to someone. Whatever you do, you're sending the same 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.

+ +
+

Extensions are explained in sections 5.8, 9, 11.3.2, and 11.4 of the spec.

+
+ +

TODO

+ +

Subprotocols

+ +

Think of a subprotocol as a custom XML schema or doctype declaration. 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.

+ +
+

Subprotocols are explained in sections 1.9, 4.2, 11.3.4, and 11.5 of the spec.

+
+ +

A client has to ask for a specific subprotocol. To do so, it will send something like this as part of the original handshake:

+ +
GET /chat HTTP/1.1
+...
+Sec-WebSocket-Protocol: soap, wamp
+
+
+ +

or, equivalently:

+ +
...
+Sec-WebSocket-Protocol: soap
+Sec-WebSocket-Protocol: wamp
+
+
+ +

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 soap and wamp. Then, in the response handshake, it'll send:

+ +
Sec-WebSocket-Protocol: soap
+
+
+ +
+

The server can't send more than one Sec-Websocket-Protocol header.
+ If the server doesn't want to use any subprotocol, it shouldn't send any Sec-WebSocket-Protocol header. Sending a blank header is incorrect.
+ The client may close the connection if it doesn't get the subprotocol it wants.

+
+ +

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 json. In this subprotocol, all data is passed as JSON. 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.

+ +
+

Tip: 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: Sec-WebSocket-Protocol: chat.example.com. For different versions, a widely-used method is to add a / followed by the version number, like chat.example.com/2.0. Note that this isn't required, it's just an optional convention, and you can use any string you wish.

+
+ + + + 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 +--- +

{{DefaultAPISidebar("Websockets API")}}

+ +

WebSockets 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.

+ +

Interfaces

+ +
+
WebSocket
+
El interfaz principal para conectar a un servidor Websocket y así enviar y recibir datos a través de la conexión.
+
CloseEvent
+
El evento enviado por el objeto WebSocket cuando se cierra la conexión.
+
MessageEvent
+
El evento enviado por el objeto WebSocket cuando se recibe un mensaje enviado desde el servidor.
+
+ +
+

Herramientas

+ + + + + + +
+ +

Ver también

+ + + +

Compatibilidad con navegadores

+ +

{{CompatibilityTable}}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CaracterísticaChromeFirefox (Gecko)Internet ExplorerOperaSafari
Versión -76  {{obsolete_inline}}6{{CompatGeckoDesktop("2.0")}}{{CompatNo}}11.00 (disabled)5.0.1
Protocolo versión 7{{CompatNo}}{{CompatGeckoDesktop("6.0")}}
+ {{property_prefix("Moz")}}
{{CompatNo}}{{CompatNo}}{{CompatNo}}
Protocolo versión 1014{{CompatGeckoDesktop("7.0")}}
+ {{property_prefix("Moz")}}
HTML5 Labs{{CompatUnknown}}{{CompatUnknown}}
RFC 6455 (IETF Draft 17)16{{CompatGeckoDesktop("11.0")}}1012.10{{CompatUnknown}}
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CaracterísticaAndroidFirefox Mobile (Gecko)IE MobileOpera MobileSafari Mobile
Versión -76  {{obsolete_inline}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
Protocolo versión 7{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
Protocolo versión 8 (IETF draft 10){{CompatUnknown}}{{CompatGeckoMobile("7.0")}}{{CompatUnknown}}{{CompatUnknown}}{{CompatUnknown}}
RFC 6455 (IETF Draft 17)16{{CompatGeckoDesktop("11.0")}}{{CompatUnknown}}12.10{{CompatUnknown}}
+
+ +

Notas para Gecko

+ +

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.

+ +

Gecko 6.0

+ +

Prior to Gecko 6.0 {{geckoRelease("6.0")}}, there was, incorrectly, a WebSocket object that some sites were thinking implied that WebSocket services were not prefixed; this object has been renamed to MozWebSocket.

+ +

Gecko 7.0

+ +

Starting in Gecko 7.0 {{geckoRelease("7.0")}}, the network.websocket.max-connections preference is used to determine the maximum number of WebSocket connections that can be open at a time. The default value is 200.

+ +

Gecko 8.0

+ +

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.

+ +

Gecko 11.0

+ +

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.

+ +

Additionally, ArrayBuffer send and receive support for binary data has been implemented.

+ +

Starting in Gecko 11.0, the WebSocket API is no longer prefixed.

+ +
Warning: Among other things, a key reason WebSockets was disabled by default in Firefox 4 and 5 is the discovery of a security issue in the protocol's design. This was fixed in Firefox 6 by implementing a newer version of the protocol that corrects the problem.
+ +
{{HTML5ArticleTOC}}
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 +--- +

{{ draft() }}

+ +

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.

+ +
Nota: 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.
+ +

Disponibilidad de WebSockets

+ +

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.

+ +
Nota: 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).
+ +

Creando un Objeto WebSocket

+ +

Para comunicarse utilizando  el protocolo webSocket, necesitarás crear un objeto WebSocket; este automáticamente abrirá una conexión temporal al servidor.

+ +

El constructor WebSocket requiere de un parámetro obligatorio y otro opcional:

+ +
WebSocket WebSocket(
+  in DOMString url,
+  in optional DOMString protocols
+);
+
+WebSocket WebSocket(
+  in DOMString url,
+  in optional DOMString[] protocols
+);
+
+ +
+
url
+
La url a la que conectar; esta es la URL a la que el WebSocket responde.
+
protocols {{ optional_inline() }}
+
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.
+
+ +

El constructor puede lanzar excepciones:

+ +
+
SECURITY_ERR
+
El puerto de la conexión está siendo bloqueado.
+
+ +
+
+ +

Errores de conexión

+ +

Si ocurre un error al intentar conectar, lo primero que recibiremos será un evento con el nombre de "error" en el objeto WebSocket (de este modo se invoca el manejador onerror), y luego CloseEvent es enviado al objeto WebSocket (de este modo se invoca el manejador onclose), para indicar la razón del cierre de la conexión.

+ +

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 RFC 6455, Section 7.4 a través de un CloseEvent.

+ +

Ejemplos

+ +

En este ejemplo de crea un nuevo WebSocket, conectandose al servidor ws://www.example.com/socketserver. El nombre del protocolo "protocolOne"  es el utilizado para la consulta del socket, aunque puede ser omitido.

+ +
var exampleSocket = new WebSocket("ws://www.example.com/socketserver", "protocolOne");
+
+ +

Como respuesta, exampleSocket.readyState es CONNECTING. El readyState será  OPEN una vez que la conexión este lista para transferir información.

+ +

Si se quiere establecer una conexión que soporte varios protocolos, se puede establecer un array de protocolos:

+ +
var exampleSocket = new WebSocket("ws://www.example.com/socketserver", ["protocolOne", "protocolTwo"]);
+
+ +

Una vez que la conexión este establecida (readyState estará OPEN), exampleSocket.protocol te dirá qué protocolo ha seleccionado el servidor.

+ +

En los ejemplos anteriores ws sustituye http, y de igual manera wss sustituye a https. 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 ws://www.example.comwss://www.example.com.

+ +

Enviando Información al servidor

+ +

Una vez la conexión esta abierta, se puede comenzar a enviar datos al servidor. Para hacer esto, simplemente se llama al metodo send() del objeto WebSocketcada vez que se desea enviar un mensaje:

+ +
exampleSocket.send("Here's some text that the server is urgently awaiting!");
+
+ +

Puedes enviar información como un string, {{ domxref("Blob") }}, o en un  ArrayBuffer.

+ +
Nota: Antes de la version 11, Firefox sólo soportaba el envío de datos como una cadena.
+ +

Como la conexión es asincronica y es propensa a fallar, no hay garantia de poder llamar al metodo send() 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 onopen:

+ +
exampleSocket.onopen = function (event) {
+  exampleSocket.send("Here's some text that the server is urgently awaiting!");
+};
+
+ +

Usando JSON para transferir Objetos

+ +

Una forma de enviar información compleja al servidor es utilizar JSON. Por ejemplo, un programa para chatear puede interactuar con el servidor usando un protocolo que implementa el uso de paquetes de JSON:

+ +
// 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 = "";
+}
+
+ +

Recibiendo mensajes del servidor

+ +

WebSockets API es un manejador de eventos; cuando el mensaje es recibido, un "message" el evento es pasado el manejador onmessage. Para escuchar la entrada de información, se puede hacer algo como lo siguiente:

+ +
exampleSocket.onmessage = function (event) {
+  console.log(event.data);
+}
+
+ +

Recibiendo e interpretando objetos JSON

+ +

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á:

+ + + +

El código que interpretará los mensajes entrantes será así:

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

Se usa JSON.parse() para convertir el objeto JSON de vuelta al original, luego se examina y se realiza la acción pertinente.

+ +

Formato de texto de los datos

+ +

El texto recibido a través de la conexión WebSocket está en formato UTF-8.

+ +

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.

+ +

Cerrando la conexión

+ +

Cuando se ha terminado de usar la conexión WebSocket, se llama el método close() del objeto WebSocket:

+ +
exampleSocket.close();
+
+ +

Puede ser de gran ayuda revisar el atributo bufferedAmount del socket para verificar que toda la información ha sido enviada antes de intentar cerrar el socket.

+ +

Consideraciones de Seguridad

+ +

Los WebSockets no deben ser usados en entornos de contenido mixto; eso es, no debes abrir una conexión de WebSocket no segura desde una página cargada usando HTTPS o viceversa. De hecho, muchos navegadores solo admiten conexiones WebSocket seguras, y ya no soportan su uso en contextos no seguros.

+ +

{{ languages ( {"zh-tw": "zh_tw/WebSockets/Writing_WebSocket_client_applications"} ) }}

-- cgit v1.2.3-54-g00ecf