Compartir a través de


Tecnología de vanguardia

Entienda el poder de WebSockets

Dino Esposito

 

Dino EspositoLa World Wide Web actual no fue diseñada para ser un medio en tiempo real. Las aplicaciones web dan la impresión de una sensación continua mediante las clásicas soluciones de sondeo implementadas a través de AJAX o, tal vez, mediante solicitudes de sondeo largo cuando están implementadas correctamente por bibliotecas ad hoc, como SignalR y Comet. Para las necesidades de la mayoría de las aplicaciones, el sondeo es una buena solución, aún cuando puede sufrir las latencias del cliente al servidor y del servidor al cliente. En este artículo, explicaré una nueva alternativa llamada WebSockets.

La creciente integración entre las aplicaciones web y móviles con los medios sociales ha disminuido la tolerancia a la demora en la interacción entre el cliente y el servidor. Cuando uno actualiza su estado en Facebook, desea que esa información esté disponible inmediatamente para los amigos. Del mismo modo, cuando a alguien le gusta una de nuestras publicaciones, queremos recibir la notificación en forma instantánea. Actualmente, todas estas funciones son reales y esta es apenas una de las razones para la adopción mundial de Facebook y de la explosión del fenómeno de las redes sociales. En definitiva, existe una importante demanda por parte de los desarrolladores de soluciones y herramientas por implementar una comunicación en tiempo real a través de la web.

Para lograr una conectividad sin retardo entre los clientes y servidores web hay que ir más allá del protocolo HTTP. Esto es justamente lo que el protocolo WebSocket proporciona. Actualmente, existe un estándar del Grupo de trabajo de ingeniería de Internet para el protocolo WebSocket; puede leer al respecto en bit.ly/va6qSS. World Wide Web Consortium (W3C) está formalizando una API estándar para implementar el protocolo, con el fin de obtener compatibilidad en los exploradores (consulte bit.ly/h1IsjB). La especificación tiene el estado “Candidato a recomendación”.

El protocolo WebSocket

El nuevo protocolo WebSocket pretende superar la limitación estructural del protocolo HTTP que lo vuelve ineficaz para las aplicaciones web alojadas en los exploradores, para que se mantengan conectados con el servidor a través de una conexión persistente. El protocolo WebSocket permite la comunicación bidireccional entre las aplicaciones web y los servidores web a través de un solo socket TCP. Dicho de otra forma, el protocolo permite que una aplicación web alojada en un explorador se mantenga conectada con el extremo web durante todo el tiempo, mientras que se incurren en costos mínimos, como la presión en el servidor y el consumo de memoria y de recursos. El efecto en la red es que los datos y las notificaciones pueden ir y venir entre los exploradores y los servidores web sin retrasos y no existe la necesidad de realizar solicitudes adicionales. Por muy enfático que suene, el protocolo WebSocket abre un nuevo mundo de posibilidades para los desarrolladores y hace que los trucos y los marcos basados en el sondeo sean cosa del pasado. Bueno, no exactamente.

El uso de WebSockets hoy

La compatibilidad de los exploradores con el protocolo WebSocket mejorará rápidamente, pero por supuesto, solo las últimas versiones de los exploradores serán compatibles con WebSockets. Los usuarios que no actualizan a menudo sus exploradores (o no pueden actualizarlos debido a políticas corporativas estrictas) quedarán rezagados.

Esto quiere decir que los desarrolladores no pueden simplemente abandonar el sondeo AJAX basado en código o las soluciones de sondeo largo. Con relación a esto, resulta importante observar que SignalR (el marco de Microsoft que está pronto a aparecer para la mensajería sin retardo entre exploradores y servidores web) realiza un trabajo fantástico a la hora de abstraer una conexión persistente, al cambiar automáticamente a WebSockets (donde sea posible) y al usar el sondeo largo en el resto de los casos. Ya analicé SignalR en algunos artículos recientes y nuevamente lo invito a que los pruebe lo antes posible, si es que aún no lo ha hecho. SignalR posee todos los elementos para ser una biblioteca ganadora y una herramienta para cada desarrollador y para cualquier aplicación web.

¿Quién es compatible con WebSockets hoy?

La Figura 1 proporciona un breve resumen de la compatibilidad con WebSockets que brinda la mayoría de los exploradores en la actualidad.

Figura 1 Compatibilidad de los exploradores con WebSockets

Explorador Compatibilidad con WebSockets
Internet Explorer Internet Explorer 10 será compatible con WebSockets. Las aplicaciones Metro escritas con JavaScript y HTML5 también serán compatibles con WebSockets.
Firefox El explorador es compatible con WebSockets a partir de la versión 6, la cual apareció a mediados del 2011. La versión 4 ofreció una compatibilidad temprana, pero esta desapareció en la versión 5.
Chrome Chrome es compatible con WebSockets a partir de la versión 14, la cual apareció en septiembre del 2011.
Opera La compatibilidad con WebSockets desapareció en la versión 11.
Safari Compatible con una versión anterior del protocolo WebSocket.

A excepción de Firefox, puede revisar la compatibilidad con WebSockets en forma programática al mirar el objeto window.WebSocket. Para Firefox, definitivamente debe revisar el objeto MozWebSocket. Debe tener presente que la mayorías de las capacidades relacionadas con HTML5 se pueden revisar en los exploradores a través de una biblioteca especializada, como Modernizr (modernizr.com). En concreto, aquí está el código JavaScript que deberá escribir si vinculó la biblioteca Modernizr con su página:

if (Modernizr.websockets)
{
  ...
}

En la actualidad, Modernizr probablemente es una excelente opción, si desea comenzar a usar la implementación de WebSocket, ya que proporciona polyfills (código que se activa automáticamente si el explorador actual no es compatible con una característica dada).

Al final, WebSockets representa una característica extremadamente atractiva, con una adopción dispareja entre los proveedores actuales. Sin embargo, Microsoft ofrece una amplia compatibilidad con WebSockets a través de la versión programada de Internet Explorer 10 y también en ASP.NET, Windows Communication Foundation (WCF) y Windows Runtime (WinRT). A pesar de lo anterior, tenga presente que todavía no existe una API estándar, por lo que la adopción temprana es una excelente señal de interés. Lo mejor que puede hacer actualmente es usar WebSockets a través de alguna capa de abstracción. Modernizr es una posible opción, si desea mantenerse cerca del metal y escribir su propio código para abrir y cerrar WebSockets. SignalR es una opción mejor si no busca un marco que conecte de manera transparente el explorador con un extremo web en forma persistente, sin lujos y sin tener que familiarizarse demasiado con los detalles subyacentes.

Una mirada al protocolo WebSocket

El protocolo WebSocket para la comunicación bidireccional requiere que tanto la aplicación cliente como servidor conozcan los detalles del protocolo. Esto quiere decir que requiere de una página web que cumpla con WebSocket y que se comunique con un extremo que cumpla con WebSocket.

La interacción de WebSocket comienza con un protocolo de enlace en el que las dos partes (explorador y servidor) confirman mutuamente su intención de comunicarse a través de una conexión persistente. A continuación, se envía un montón de paquetes de mensajes a través de TCP en ambas direcciones. La Figura 2 destaca cómo funciona el protocolo WebSocket.

The WebSocket Protocol Schema
Figura 2 Esquema del protocolo WebSocket

Observe que además de lo que aparece en la Figura 2, cuando se cierra la conexión, ambos extremos intercambian un marco de cierre para cerrar la conexión en forma limpia. El enlace inicial consiste en una simple solicitud HTTP que el cliente envía al servidor web. La solicitud es una instrucción HTTP GET configurada como una solicitud de actualización:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com

En HTTP, una solicitud del cliente con un encabezado de actualización indica que el cliente tiene la intención de solicitarle un cambio de protocolo al servidor. Con el protocolo WebSocket, la solicitud de actualización al servidor contiene una clave única que el servidor devolverá modificada, como prueba de que aceptó la solicitud de actualización. Esta demostración práctica muestra que el servidor comprende el protocolo WebSocket. Aquí vemos un ejemplo de una respuesta a una solicitud de enlace:

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

El código de estado satisfactorio siempre es 101 y cualquier otro código de estado se interpreta como una negativa a cambiar al protocolo WebSocket. El servidor concatena la clave recibida con una cadena GUID fija y calcula un valor hash a partir de la cadena resultante. Luego, lo codifica en Base64 y lo devuelve al cliente a través del encabezado Sec-WebSocket-Accept.

El cliente también puede enviar otros encabezados como Sec-WebSocket-Protocol, para indicar los subprotocolos que puede aceptar. Un subprotocolo es un protocolo en el nivel de la aplicación creado sobre el protocolo WebSocket básico. Si el servidor comprende alguno de los subprotocolos sugeridos, elegirá uno y enviará su nombre de vuelta al cliente a través del mismo encabezado.

Después del protocolo de enlace, el cliente y el servidor pueden enviar mensajes libremente a través del protocolo WebSocket. La carga comienza con un código de operación que señala la operación que se está llevando a cabo. Uno de estos códigos de operación (específicamente 0x8) indica una solicitud para cerrar la sesión. Observe que los mensajes de WebSocket se transmiten de manera asincrónica, por lo que las solicitudes enviadas no recibirán necesariamente una respuesta inmediata, como en HTTP. Con el protocolo WebSocket, conviene pensar en términos de mensajes generales que van del cliente al servidor o viceversa y olvidar los patrones clásicos de solicitud y respuesta de HTTP.

La dirección URL típica de un extremo WebSocket adopta la siguiente forma:

var myWebSocket =
    new WebSocket("ws://www.websocket.org");

Cuando deseamos usar una conexión de socket segura (por lo general, las conexiones seguras funcionan mejor cuando existen intermediarios), usamos el prefijo de protocolo wss. Finalmente, el protocolo WebSocket reconoce y aborda el problema de la comunicación de origen cruzado. Los clientes WebSocket generalmente (pero no siempre) permiten enviar las solicitudes hacia extremos ubicados en cualquier dominio. Pero es el servidor WebSocket el que decide aceptar o rechazar la solicitud de enlace.

Una mirada a la API de WebSocket

Tal como mencionamos, W3C está estandarizando actualmente una API para el protocolo WebSocket y los exploradores se van poniendo al día con los diferentes borradores, a medida que estos van apareciendo. Debe tener muy claro que cualquier código que funciona hoy puede no funcionar en todos los exploradores y, más importante aun, no hay ninguna garantía de que funcione en las versiones futuras del mismo explorador. Sea cual sea el caso, cuando cuente con un código WebSocket que funcione, estará prácticamente listo, ya que cualquier cambio que sea necesario en el futuro será, de seguro, nada más que pequeñas modificaciones.

Si desea experimentar con el protocolo WebSocket, puede visitar websocket.org con un explorador compatible con el protocolo. Por ejemplo, puede usar una vista previa de Internet Explorer 10 o una versión reciente de Google Chrome. En la Figura 3 vemos cómo aparece el protocolo de enlace en Fiddler.

Real Handshaking Between Browser and Server
Figura 3 Protocolo de enlace real entre el explorador y el servidor

No es de sorprender que la versión actual de Fiddler (versión 2.3.x) solo captura el tráfico HTTP. Sin embargo, existe una versión beta de Fiddler que también reconoce el tráfico WebSocket.

La API de WebSocket es bastante simple. Del lado explorador, tenemos que crear una instancia de la clase WebSocket del explorador. Esta clase expone varios eventos interesantes que requieren de controladores apropiados:

var wsUri = " ws://echo.websocket.org/";
websocket = new WebSocket(wsUri);
websocket.onopen = function(evt) { onOpen(evt) };
websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onclose = function(evt) { onClose(evt) };
websocket.onerror = function(evt) { onError(evt) };

El evento onopen se activa cuando se establece la conexión. El evento onmessage se activa siempre que un cliente recibe un mensaje del servidor. El evento onclose se activa cuando la conexión se cierra. Por último, onerror se activa cada vez que ocurre un error.

Para enviar un mensaje al servidor, lo único que debemos hacer es realizar una llamada al método enviar, tal como vemos aquí:

var message = "Cutting Edge test: " +
  new Date().toString();
websocket.send(message);

La Figura 4 muestra una página de ejemplo que corresponde a una adaptación del ejemplo de eco que se encuentra en el sitio web websocket.org. En este ejemplo, el servidor simplemente devuelve un eco del mensaje recibido al cliente.

The WebSocket Protocol in ActionFigura 4 El protocolo WebSocket en acción

Si está interesado en la programación de WebSocket para Internet Explorer 10, consulte bit.ly/GNYWFh.

WebSockets del lado servidor

En este artículo me centré principalmente en el lado cliente del protocolo WebSocket. Debe quedar claro que para poder usar un cliente WebSocket hace falta un servidor compatible con WebSocket que entienda las solicitudes y pueda responder de manera apropiada. Han comenzado a aparecer marcos para crear servidores WebSocket. Por ejemplo, puede probar Socket.IO para Java y Node.js (socket.io). Si busca algo relacionado con Microsoft .NET Framework, eche una mirada a “Servidor Web Socket” de The Code Project en bit.ly/lc0rjt. Además, IIS, ASP.NET y WCF de Microsoft Server son compatibles con WebSockets. Para obtener más información, puede consultar el vídeo de Channel 9, “Creación de aplicaciones web de tiempo real con WebSockets con IIS, ASP.NET y WCF,” (bit.ly/rnYaw5).

Pólvora, agua caliente y WebSockets

Muchas personas han dicho que WebSockets es el invento más útil después de la pólvora y el agua caliente. Después de comprender WebSockets, solo queda preguntarnos cómo el mundo del software logró prosperar previamente. WebSockets resulta útil para varias aplicaciones, pero no para cualquier aplicación. Cualquier aplicación donde la mensajería instantánea sea un elemento clave resulta un contexto potencial en el que puede plantearse seriamente la posibilidad de crear un servidor WebSocket con un conjunto de clientes (web, móviles o incluso de escritorio). Los juegos y las aplicaciones con fuentes en directo corresponden a otros ámbitos de la industria que se beneficiarán enormemente del protocolo WebSocket. ¡Sí, WebSockets definitivamente es lo mejor después del agua caliente!

Dino Esposito* es autor de “Programming ASP.NET 4” (Microsoft Press, 2011) y “Programming ASP.NET MVC 3” (Microsoft Press, 2010) y coautor de “Microsoft .NET: Architecting Applications for the Enterprise” (Microsoft Press, 2008). Con residencia en Italia, Esposito participa habitualmente en conferencias y eventos del sector en todo el mundo. Puede seguir a Dino por Twitter en twitter.com/despos.*

Gracias a los siguientes expertos técnicos por su ayuda en la revisión de este artículo: Levi Broderick y Brian Raymor