WebSockets: comunicación con el servidor

La Web se ha construido en gran medida en torno al paradigma de solicitud / respuesta de HTTP. Un cliente carga una página web y luego no pasa nada hasta que el usuario hace clic en la página siguiente. Alrededor de 2005, AJAX comenzó a hacer que la web se sintiera más dinámica. Aún así, toda la comunicación HTTP es dirigida por el cliente, lo que requiere la interacción del usuario o sondeos periódicos para cargar nuevos datos desde el servidor.

Las tecnologías que permiten al servidor enviar los datos a un cliente en el mismo momento en que sabe que hay nuevos datos disponibles existen desde hace bastante tiempo. Van por nombres como"Push" o “Comet”.

Con long polling, el cliente abre una conexión HTTP al servidor, que lo mantiene abierto hasta que envía la respuesta. Siempre que el servidor tiene datos nuevos, envía la respuesta. El sondeo largo y las otras técnicas funcionan bastante bien. Sin embargo, todos estos comparten un problema, llevan la sobrecarga de HTTP, lo que no los hace adecuados para aplicaciones de baja latencia. Por ejemplo, un juego de disparos multijugador en el navegador o cualquier otro juego en línea con un componente en tiempo real.

Llevando Sockets a la Web

La especificación Web Socket define una API que establece conexiones de "socket" entre un navegador web y un servidor. En términos simples, existe una conexión persistente entre el cliente y el servidor y ambas partes pueden comenzar a enviar datos en cualquier momento.

La conexión de socket web se puede abrir simplemente usando un constructor -

var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);

wses el nuevo esquema de URL para las conexiones WebSocket. También haywss, para una conexión segura WebSocket de la misma manera https se utiliza para conexiones HTTP seguras.

Adjuntar algunos controladores de eventos inmediatamente a la conexión le permite saber cuándo se abre la conexión, se reciben mensajes entrantes o hay un error.

El segundo argumento acepta opcional subprotocols. Puede ser una cadena o una matriz de cadenas. Cada cadena debe representar unsubprotocol nombre y servidor acepta solo uno de los pasados subprotocolsen la matriz. Aceptadosubprotocol se puede determinar accediendo a la propiedad de protocolo del objeto WebSocket.

// When the connection is open, send some data to the server
connection.onopen = function () {
   connection.send('Ping'); // Send the message 'Ping' to the server
};

// Log errors
connection.onerror = function (error) {
   console.log('WebSocket Error ' + error);
};

// Log messages from the server
connection.onmessage = function (e) {
   console.log('Server: ' + e.data);
};

Comunicarse con el servidor

Tan pronto como tengamos una conexión con el servidor (cuando se active el evento de apertura), podemos comenzar a enviar datos al servidor utilizando el método de envío (su mensaje) en el objeto de conexión. Solía ​​admitir solo cadenas, pero en la última especificación, ahora también puede enviar mensajes binarios. Para enviar datos binarios, se utiliza el objeto Blob o ArrayBuffer.

// Sending String
connection.send('your message');

// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);

for (var i = 0; i < img.data.length; i++) {
   binary[i] = img.data[i];
}

connection.send(binary.buffer);

// Sending file as Blob
var file = document.querySelector('input[type = "file"]').files[0];
connection.send(file);

Igualmente, el servidor puede enviarnos mensajes en cualquier momento. Siempre que esto sucede, se activa la devolución de llamada onmessage. La devolución de llamada recibe un objeto de evento y se puede acceder al mensaje real a través de la datapropiedad.

WebSocket también puede recibir mensajes binarios con las últimas especificaciones. Los fotogramas binarios se pueden recibir en formato Blob o ArrayBuffer. Para especificar el formato del binario recibido, establezca la propiedad binaryType del objeto WebSocket en 'blob' o 'arraybuffer'. El formato predeterminado es 'blob'.

// Setting binaryType to accept received binary as either 'blob' or 'arraybuffer'
connection.binaryType = 'arraybuffer';
connection.onmessage = function(e) {
   console.log(e.data.byteLength); // ArrayBuffer object if binary
};

Otra característica recientemente agregada de WebSocket son las extensiones. Mediante extensiones, será posible enviar tramas comprimidas, multiplexadas, etc.

// Determining accepted extensions
console.log(connection.extensions);

Comunicación de origen cruzado

Al ser un protocolo moderno, la comunicación de origen cruzado se integra directamente en WebSocket. WebSocket permite la comunicación entre partes en cualquier dominio. El servidor decide si su servicio está disponible para todos los clientes o solo para aquellos que residen en un conjunto de dominios bien definidos.

Servidores proxy

Cada nueva tecnología viene con una nueva serie de problemas. En el caso de WebSocket es la compatibilidad con servidores proxy, que median las conexiones HTTP en la mayoría de las redes de empresas. El protocolo WebSocket usa el sistema de actualización HTTP (que normalmente se usa para HTTP / SSL) para "actualizar" una conexión HTTP a una conexión WebSocket. A algunos servidores proxy no les gusta esto y cortarán la conexión. Por lo tanto, incluso si un cliente determinado utiliza el protocolo WebSocket, es posible que no sea posible establecer una conexión. Esto hace que la siguiente sección sea aún más importante :)

El lado del servidor

El uso de WebSocket crea un patrón de uso completamente nuevo para las aplicaciones del lado del servidor. Si bien las pilas de servidores tradicionales, como LAMP, están diseñadas en torno al ciclo de solicitud / respuesta HTTP, a menudo no se adaptan bien a una gran cantidad de conexiones WebSocket abiertas. Mantener una gran cantidad de conexiones abiertas al mismo tiempo requiere una arquitectura que reciba alta concurrencia a un bajo costo de rendimiento.