Cutting Edge

Compreendendo o poder dos WebSockets

Dino Esposito

 

Dino EspositoA World Wide Web atual não foi projetada como uma mídia em tempo real. Os aplicativos Web dão a impressão de percepção contínua por meio de soluções de sondagem implementadas por meio do AJAX ou talvez por meio de solicitações de pesquisas longas quando implementadas efetivamente por bibliotecas ad hoc, como SignalR e Comet. Para as necessidades da maioria dos aplicativos, a sondagem é uma boa solução, mesmo que ela possa sofrer com a latência de cliente para servidor e de servidor para cliente. Neste artigo, explorarei uma nova alternativa chamada WebSocket.

A integração cada vez maior entre aplicativos Web e móveis com a mídia social está reduzindo o limite de atraso tolerável na interação entre cliente e servidor. Quando atualiza seu status no Facebook, você quer que as informações sejam disponibilizadas imediatamente para seus amigos. Da mesma forma, quando alguém gosta de uma de suas postagens, você quer ser notificado instantaneamente. Atualmente, todos esses recursos são reais, e essa é apenas uma das razões da adoção mundial do Facebook e da explosão do fenômeno de redes sociais. Portanto, no final, há uma demanda significativa dos desenvolvedores por soluções e ferramentas para a implementação de comunicação em tempo real pela Web.

Obter conectividade com zero latência entre clientes e servidores Web requer que você vá além do protocolo HTTP. Isso é exatamente o que o protocolo WebSocket fornece. Atualmente, existe um padrão da Internet Engineering Task Force para o protocolo WebSocket. Você pode ler a respeito no bit.ly/va6qSS. Uma API padrão para a implementação do protocolo está sendo formalizada pelo World Wide Web Consortium (W3C) para que os navegadores deem suporte a ele (consulte o bit.ly/h1IsjB). A especificação está no status de “Candidate Recommendation”.

Protocolo WebSocket

O novo protocolo WebSocket tem o objetivo de superar a limitação estrutural do protocolo HTTP, que é ineficiente para que os aplicativos Web hospedados em navegadores permaneçam conectados com o servidor em uma conexão persistente. O protocolo WebSocket permite comunicação bidirecional entre os aplicativos e servidores Web por meio de um único soquete TCP. Colocado de outra forma, o protocolo permite que um aplicativo Web hospedado em um navegador permaneça conectado com um ponto de extremidade Web durante todo o tempo e, ao mesmo tempo, incorra em custos mínimos, como pressão no servidor, memória e consumo de recursos. O efeito líquido é que os dados e as notificações podem ir e vir entre os navegadores e servidores Web sem nenhum atraso e nenhuma necessidade de organizar solicitações adicionais. Por mais exagerado que pareça, o protocolo WebSocket abre um mundo completamente novo de possibilidades para os desenvolvedores e torna os truques e as estruturas baseadas em sondagem uma coisa do passado. Bem, não exatamente.

Usando o WebSocket atualmente

O suporte dos navegadores ao protocolo WebSocket melhorará rapidamente, mas, naturalmente, apenas as versões mais recentes dos navegadores darão suporte ao WebSocket. Os usuários que não atualizarem seus navegadores regularmente (ou não tiverem permissão para atualizar devido a políticas corporativas) serão deixados para trás.

Isso significa que os desenvolvedores não podem simplesmente abandonar o código baseado no AJAX ou as soluções de sondagem longa. Em relação a isso, é importante observar que o SignalR, a futura estrutura da Microsoft para sistemas de mensagens com zero latência entre navegadores e servidores Web, funciona fantasticamente para abstrair uma conexão persistente, alternando automaticamente para o WebSocket, quando houver suporte, e usando sondagem longa em quaisquer outros casos. Abordei o SignalR em colunas recentes e, mais uma vez, convido você a experimentá-lo assim que possível, caso ainda não o tenha feito. O SignalR tem tudo para ser uma biblioteca vencedora e uma ferramenta para todos os desenvolvedores e qualquer aplicativo Web.

Quem dá suporte ao WebSocket atualmente?

A Figura 1 fornece um breve resumo do suporte ao WebSocket fornecido pelos navegadores mais populares.

Figura 1 Suporte dos navegadores ao WebSocket

Navegador Suporte ao WebSocket
Internet Explorer O WebSocket terá suporte no Internet Explorer 10. Os aplicativos Metro criados com o JavaScript e o HTML5 também darão suporte ao WebSocket.
Firefox O WebSocket tem suporte a partir da versão 6 do navegador liberada em meados de 2011. Um suporte muito precoce foi oferecido na versão 4 e, em seguida, removido na versão 5.
Chrome O WebSocket tem suporte a partir da versão 14, que foi liberada em setembro de 2011.
Opera O suporte ao WebSocket foi removido na versão 11.
Safari Dá suporte a uma versão anterior do protocolo WebSocket.

Com exceção do Firefox, é possível verificar o suporte ao WebSocket de forma programática examinando o objeto window.WebSocket. No Firefox, você deve verificar o objeto MozWebSocket. É necessário observar que a maioria dos recursos relacionados ao HTML5 podem ser verificados nos navegadores por meio de uma biblioteca especializada, como a Modernizr (modernizr.com). Particularmente, este é o código JavaScript que precisa ser criado ao vincular a biblioteca Modernizr à sua página:

if (Modernizr.websockets)
{
  ...
}

A Modernizr, provavelmente, será uma excelente opção atualmente, se você desejar começar a usar uma implementação do WebSocket uma vez que ela fornece o polyfills, um código que entra em operação automaticamente quando um determinado recurso não tem suporte no navegador atual.

No final, o WebSocket é um recurso extremamente convincente, mas atualmente não tem suporte uniforme entre os fornecedores. No entanto, a Microsoft dá amplo suporte ao WebSocket por meio do futuro Internet Explorer 10 e também do IIS, do ASP.NET, do Windows Communication Foundation (WCF) e do Windows Runtime (WinRT). Observe, porém, que ainda não existe nenhuma API padrão oficial e, portanto, o suporte inicial é um grande sinal de interesse. O melhor a fazer hoje é usar o WebSocket por meio uma camada de abstração. A Modernizr é uma opção possível se você desejar ficar atualizado e criar seu próprio código que abra e feche o WebSocket. O SignalR é a melhor opção se você estiver procurando uma estrutura que se conecte transparentemente a um navegador e a um ponto de extremidade da Web de uma maneira persistente, sem sofisticações e nenhuma necessidade de conhecer muitos detalhes subjacentes.

Visão geral do protocolo WebSocket

O protocolo WebSocket para comunicação bidirecional requer que os aplicativos cliente e servidor reconheçam os detalhes do protocolo. Isso significa que você precisa de uma página da Web que chame um ponto de extremidade compatível com o WebSocket.

Uma interação com o WebSocket começa com um handshake no qual as duas partes (navegador e servidor) confirmam mutuamente sua intenção de se comunicar por meio de uma conexão persistente. Em seguida, vários pacotes de mensagens são enviados por meio de TCP nas duas direções. A Figura 2 descreve como o protocolo WebSocket funciona.

The WebSocket Protocol Schema
Figura 2 O esquema do protocolo WebSocket

Observe que, além do que é mostrado na Figura 2, quando a conexão é fechada, os dois pontos de extremidade trocam um quadro de fechamento para fechar a conexão corretamente. O handshake inicial consiste em uma solicitação HTTP simples que o cliente envia ao servidor Web. A solicitação é um HTTP GET configurado como uma solicitação de atualização:

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

No HTTP, uma solicitação de cliente com o cabeçalho Upgrade indica a intenção do cliente de solicitar que o servidor alterne para outro protocolo. Com o protocolo WebSocket, a solicitação de atualização para o servidor contém uma chave exclusiva que o servidor retornará desfigurada como a comprovação de que aceitou a solicitação de atualização. Essa é uma demonstração prática para mostrar que o servidor compreende o protocolo WebSocket. Esta é uma resposta de exemplo a uma solicitação de handshake:

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

Um código de status bem-sucedido é sempre 101, e qualquer outro código de status será interpretado como uma recusa de atualizar para o protocolo WebSocket. O servidor concatena a chave recebida com uma cadeia de caracteres de GUID fixa e calcula um hash a partir da cadeia de caracteres resultante. Em seguida, o valor do hash é codificado como Base64 e retornado ao cliente por meio do cabeçalho Sec-WebSocket-Accept.

O cliente também pode enviar outros cabeçalhos, como o Sec-WebSocket-­Protocol, para indicar quais subprotocolos pode empregar. Um subprotocolo é um protocolo em nível de aplicativo baseado no protocolo WebSocket básico. Se entender alguns dos protocolos sugeridos, o servidor escolherá um e enviará seu nome de volta ao cliente por meio do mesmo cabeçalho.

Depois do handshake, o cliente e o servidor podem enviar mensagens livremente pelo protocolo WebSocket. A carga começa com um opcode que indica que a operação que está sendo executada. Um desses opcodes, especificamente o 0x8, indica uma solicitação para fechar a sessão. Observe que as mensagens do WebSocket ocorrem assincronamente e, portanto, uma solicitação de envio não receberá necessariamente uma resposta imediata, como no HTTP. Com o protocolo WebSocket, é melhor você pensar em termos de mensagens gerais indo do cliente para o servidor e vice-versa e esquecer o padrão clássico de solicitação/resposta do HTTP.

A URL típica para um ponto de extremidade do WebSocket toma a seguinte forma:

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

Você usará o prefixo do protocolo wss se desejar usar uma conexão de soquete segura (conexões seguras geralmente serão mais bem-sucedidas quando intermediários estiverem presentes). Finalmente, o protocolo WebSocket confirma e resolve o problema de comunicação entre origens. Um cliente do WebSocket geralmente, mas não sempre, permite enviar solicitações a pontos de extremidade localizados em qualquer domínio. Mas é o servidor WebSocket que decidirá se deve aceitar ou rejeitar a solicitação de handshake.

Visão geral da API WebSocket

Conforme mencionado, o W3C está atualizando atualmente uma API para o protocolo WebSocket, e os navegadores estão se adequando com os vários rascunhos à medida que eles são disponibilizados. Você deve se lembrar de que qualquer código que funcione hoje poderá não funcionar entre todos os navegadores e, o mais importante, não há garantia de que ele funcionará no mesmo navegador quando uma nova versão entrar no mercado. Em todo caso, quando tiver algum código WebSocket funcionando você estará quase pronto, uma vez, que as alterações que poderão ser necessárias no futuro, muito provavelmente, serão apenas alterações menores.

Se desejar experimentar o protocolo WebSocket, visite o websocket.org com um navegador que dê suporte ao protocolo. Por exemplo, você pode usar uma visualização do Internet Explorer 10 ou uma versão recente do Google Chrome. A Figura 3 mostra o handshake conforme ele está sendo acompanhado pelo Fiddler.

Real Handshaking Between Browser and Server
Figura 3 Handshake real entre o navegador e o servidor

Não surpreendentemente, a versão atual do Fiddler (2.3.x) capturará apenas o tráfego HTTP. No entanto, a nova versão do Fiddler, que trata do tráfego WebSocket, está em beta no momento.

A API WebSocket é bem simples. No lado do navegador, você precisa criar uma instância da classe WebSocket do navegador. Essa classe expõe vários eventos interessantes para os quais você deseja ter manipuladores adequados:

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

O evento onopen é acionado quando a conexão é estabelecida. O evento onmessage é acionado sempre que o cliente recebe uma mensagem do servidor. O onclose é acionado quando a conexão foi fechada. Finalmente, o onerror é acionado sempre que ocorre um erro.

Para enviar uma mensagem ao servidor, tudo o que você precisa fazer é colocar uma chamada para o método send, conforme mostrado a seguir:

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

A Figura 4 mostra uma página de exemplo que é uma adaptação do exemplo de eco localizado no site websocket.org. Neste exemplo, o servidor apenas ecoa a mensagem recebida de volta para o cliente.

The WebSocket Protocol in Action
Figura 4 O protocolo WebSocket em ação

Se estiver interessado na programação do WebSocket para o Internet Explorer 10, consulte bit.ly/GNYWFh.

O lado do servidor do WebSocket

Neste artigo, focalizei o lado do cliente do protocolo WebSocket. Deve ficar claro que, para usar um cliente WebSocket, você precisa de um servidor adequado compatível com o WebSocket, que compreenda as solicitações e possa responder de maneira adequada. Começaram a aparecer estruturas para a criação de um servidor WebSocket. Por exemplo, você pode tentar o Socket.IO para Java e Node.js (socket.io). Se estiver procurando material do Microsoft .NET Framework, consulte “Servidor Web Socket” no The Code Project em bit.ly/lc0rjt. Além disso, o suporte para o servidor Microsoft para WebSocket está disponível no IIS, no ASP.NET e no WCF. Você pode assistir ao vídeo do Channel 9, “Criando aplicativos Web de tempo real com o WebSocket usando IIS, ASP.NET e WCF” para obter mais detalhes (bit.ly/rnYaw5).

Pão em fatias, água quente e WebSocket

Como já declarado por muitos, o WebSocket é a invenção mais útil desde o pão em fatias e a água quente. Depois de decifrar o WebSocket, você não poderá imaginar como o mundo do software progrediu sem ele. O WebSocket é útil para vários aplicativos, mas não para todos. Qualquer aplicativo em que o sistema de mensagens instantâneas é importante é um cenário potencial, onde você poderá considerar seriamente a criação de um servidor WebSocket e vários clientes Web, aplicativos móveis e até áreas de trabalho. Os aplicativos de jogo e de feed ativo são outras áreas do setor que se beneficiarão muito com o protocolo WebSocket. Sim, o WebSocket é definitivamente o melhor depois da água quente!

Dino Esposito é o autor de “Programming Microsoft ASP.NET 4” (Microsoft Press, 2011) e “Programming ASP.NET MVC 3” (Microsoft Press, 2010) e coautor de “Microsoft .NET: Architecting Applications for the Enterprise” (Microsoft Press, 2008). Residente na Itália, Esposito é um palestrante sempre presente em eventos do setor no mundo inteiro. Siga-o no Twitter em twitter.com/despos.

Agradecemos aos seguintes especialistas técnicos pela revisão deste artigo: Levi Broderick e Brian Raymor