Artigo - WebSocket ULBRA

19
1 IMPLEMENTAÇÃO E ANÁLISE DA UTILIZAÇÃO DE WEBSOCKETS EM SISTEMAS COMPUTACIONAIS Thiago Daniel R. Varela Orientador: Stanley Loh Universidade Luterana do Brasil (ULBRA) – Ciência da Computação Canoas – RS – Brasil thiagodrv AT gmail.com, loh AT ulbra.br RESUMO As transformações sofridas pela web, que a tornaram uma plataforma para aplicações distribuídas e altamente dinâmicas, obrigaram o surgimento de alternativas ao padrão de simples requisição/resposta do HTTP. A mais amplamente utilizada nos dias de hoje é um conjunto de tecnologias que, quando empregadas simultaneamente e com este propósito, recebem o nome de AJAX. Entretanto, mesmo esta solução representa apenas um passo na evolução da web, pois apresenta limitações já que, em última análise, ainda se baseia no modelo de requisição/resposta. Neste contexto, surge o Websocket, um novo padrão que possibilita comunicações de duas vias reais e de maneira eficiente, através de um protocolo de encapsulamento simples, de modo a proporcionar a interatividade e dinamismo que a web atual exige além da eficiência na utilização dos recursos computacionais, que é uma necessidade diante do número cada vez mais crescente de usuários. Este artigo propõe a implementação de bibliotecas implementado o protocolo, de maneira que possam ser utilizadas para a construção de novas aplicações utilizando a tecnologia de Websockets. Palavras-chave: websocket, web, http, ajax, interatividade, web dinâmica 1 INTRODUÇÃO A web sofreu grandes mudanças em seu padrão de utilização desde que foi criada, especialmente na última década. Inicialmente utilizada para transferir simples páginas estáticas compostas principalmente por texto, hoje a web serve de plataforma para sistemas com alta interatividade e cada vez mais dinâmicos. O modelo de comunicação baseado em Requisição/Resposta, sobre o qual a web foi construída, passou a mostrar-se inadequado para este novo paradigma. Em resposta a estas necessidades, surgiram diversas técnicas com o objetivo de simular uma comunicação bidirecional através deste modelo de requisição/resposta, utilizando para isso alguma variação de técnicas de polling. Entretanto, por possuírem natureza não disruptiva, estas soluções não puderam resolver a causa do problema, apenas trabalharam para contorná-lo criando mecanismos que operassem sobre a tecnologia já existente e em utilização, o que faz com que estas soluções percam em eficiência e limitem a evolução para sistemas mais interativos e mais dinâmicos. É neste cenário que surge a proposta do Websocket, um mecanismo para comunicação bidirecional que tenta tornar simples e eficiente esta interação, resolvendo o problema em sua causa mas ao mesmo tempo buscando funcionar juntamente com a estrutura atual. 2 MOTIVAÇÃO Apesar de ser um padrão relativamente novo e ainda em especificação, o Websocket já possui um número razoável de implementações funcionais, por exemplo nos navegadores Chrome e diversos outros

Transcript of Artigo - WebSocket ULBRA

1

IMPLEMENTAÇÃO E ANÁLISE DA UTILIZAÇÃO DE

WEBSOCKETS EM SISTEMAS

COMPUTACIONAIS

Thiago Daniel R. Varela

Orientador: Stanley Loh

Universidade Luterana do Brasil (ULBRA) – Ciência da Computação

Canoas – RS – Brasil

thiagodrv AT gmail.com, loh AT ulbra.br

RESUMO

As transformações sofridas pela web, que a tornaram uma plataforma para aplicações distribuídas e

altamente dinâmicas, obrigaram o surgimento de alternativas ao padrão de simples requisição/resposta do HTTP.

A mais amplamente utilizada nos dias de hoje é um conjunto de tecnologias que, quando empregadas

simultaneamente e com este propósito, recebem o nome de AJAX. Entretanto, mesmo esta solução representa

apenas um passo na evolução da web, pois apresenta limitações já que, em última análise, ainda se baseia no

modelo de requisição/resposta. Neste contexto, surge o Websocket, um novo padrão que possibilita

comunicações de duas vias reais e de maneira eficiente, através de um protocolo de encapsulamento simples, de

modo a proporcionar a interatividade e dinamismo que a web atual exige além da eficiência na utilização dos

recursos computacionais, que é uma necessidade diante do número cada vez mais crescente de usuários. Este

artigo propõe a implementação de bibliotecas implementado o protocolo, de maneira que possam ser utilizadas

para a construção de novas aplicações utilizando a tecnologia de Websockets.

Palavras-chave: websocket, web, http, ajax, interatividade, web dinâmica

1 INTRODUÇÃO

A web sofreu grandes mudanças em seu padrão de utilização desde que foi criada, especialmente

na última década. Inicialmente utilizada para transferir simples páginas estáticas compostas

principalmente por texto, hoje a web serve de plataforma para sistemas com alta interatividade e cada vez

mais dinâmicos. O modelo de comunicação baseado em Requisição/Resposta, sobre o qual a web foi

construída, passou a mostrar-se inadequado para este novo paradigma.

Em resposta a estas necessidades, surgiram diversas técnicas com o objetivo de simular uma

comunicação bidirecional através deste modelo de requisição/resposta, utilizando para isso alguma

variação de técnicas de polling.

Entretanto, por possuírem natureza não disruptiva, estas soluções não puderam resolver a causa

do problema, apenas trabalharam para contorná-lo criando mecanismos que operassem sobre a tecnologia

já existente e em utilização, o que faz com que estas soluções percam em eficiência e limitem a evolução

para sistemas mais interativos e mais dinâmicos.

É neste cenário que surge a proposta do Websocket, um mecanismo para comunicação

bidirecional que tenta tornar simples e eficiente esta interação, resolvendo o problema em sua causa mas

ao mesmo tempo buscando funcionar juntamente com a estrutura atual.

2 MOTIVAÇÃO

Apesar de ser um padrão relativamente novo e ainda em especificação, o Websocket já possui um

número razoável de implementações funcionais, por exemplo nos navegadores Chrome e diversos outros

2

baseados em WebKit. Entretanto, uma segunda utilidade para protocolos Web são os chamados

Webservices, que nada mais é do que a utilização de protocolos e padrões Web para a comunicação entre

dois ou mais sistemas ou programas, ao invés de ser uma interação sistema-usuário (como é na Web).

Este ramo de aplicação ainda carece de implementações práticas do protocolo Websocket, que poderia

trazer grandes benefícios em diversas aplicações com o seu modelo de comunicação bidirecional de

conexão única.

3 OBJETIVOS

Os objetivos que desejam-se atingir com este trabalho são, primariamente, a criação de uma

implementação genérica e funcional do protocolo Websocket, tanto do cliente quanto do servidor, na

forma de bibliotecas independentes, já que hoje as únicas implementações completas do protocolo são

embutidas dentro de grandes sistemas já prontos (como navegadores de internet), o que torna a sua

utilização muito difícil para novos sistemas que queiram tirar proveito desta nova tecnologia, permitindo,

desta forma, a criação, de maneira relativamente simples, de programas e sistemas utilizando este novo

protocolo. Esta implementação será licenciada sob uma licença livre (reconhecida como tal pela OSI –

Open Source Initiative) e permissiva, efetivamente tornando estas bibliotecas um software livre e de

código aberto, de maneira a poder ser utilizado pelo maior número de sistemas possível (comerciais ou

livres), e possibilitando também contribuições que poderão melhorar mais rapidamente a qualidade da

implementação. O objetivo último deste trabalho é a disseminação desta nova tecnologia para que o

maior número possível de pessoas possa se beneficiar dela.

4 REFERENCIAL TEÓRICO

Nas subseções a seguir, descrevem-se as principais tecnologias relacionadas ou abordadas neste

artigo.

4.1 HTTP

O HTTP é o protocolo que serve de base para toda a web. É um protocolo de camada de

aplicação, em uso na World-Wide Web global information initiative desde 1990. É um protocolo sem

estado (stateless), baseado no modelo de Requisição/Resposta. Um cliente estabelece uma conexão com

o servidor e envia uma requisição, que consiste de um método, um URI, e a versão do protocolo,

seguidos possivelmente por modificadores de requisição e informações sobre o cliente. O servidor

responde com uma linha de status, incluindo a versão do protocolo e um código de erro ou sucesso,

seguidos por uma mensagem contendo informações sobre o servidor e o corpo de dados do objeto

requisitado. (Berners-Lee et al, 1996).

A figura 1 mostra um exemplo de uma requisição HTTP em sua forma mínima e sua respectiva

resposta.

4.2 Sistemas Web Dinâmicos

As transformações no padrão de utilização da web na última década, impulsionadas

principalmente pelo surgimento de diversas plataformas cada vez mais dinâmicas e interativas, como

Gmail, Facebook e Orkut (surgidos em 2004), MySpace (criado em 2003) e Twitter (surgido em 2006),

apontam para a transformação da web, de uma simples rede de transferência de documentos estáticos, em

uma verdadeira plataforma para sistemas de larga escala, dinâmicos, sociais e interativos.

Diante deste novo paradigma, as antigas soluções começaram a mostrar-se inadequadas, pois o

modelo de requisição/resposta passou a não mais se enquadrar ao perfil destas novas plataformas, que

requerem um nível cada vez maior de interatividade, além do suporte a um número rapidamente crescente

de usuários.

3

Requisição:

GET /exemplo HTTP/1.0

Resposta:

HTTP/1.0 200

<conteúdo do objeto /exemplo>

Figura 1 – Exemplo de requisição e resposta HTTP

4.3 A Solução Atual para Comunicações Dinâmicas via Web

Com o surgimento desta demanda por maior interatividade, surgiram soluções para tornar a

interação com a web mais dinâmica.

A tecnologia predominantemente empregada nestes casos é algo que se chama de AJAX, que na

verdade não constutui por si uma tecnologia, mas sim várias técnicas diferentes sendo empregadas em

conjunto. Consiste basicamente em criar um motor de renderização da tela (na maioria dos casos em

Javascript), que é quem faz a interação com o usuário, interagindo com o servidor (na maioria dos casos

utilizando XML) assincronamente no plano de fundo. Desta maneira, o usuário não tem mais a

necessidade de ficar aguardando a resposta do servidor após cada requisição, pois o motor de

renderização pode previamente solicitar os recursos necessários, além de possibilitar a atualização de

apenas partes da tela, permitindo que o usuário continue interagindo com parte da aplicação enquanto

outra parte está sendo processada pelo servidor. (Jesse J. Garrett, 2005)

Entretando, este tipo de tecnologia ainda não permite uma comunicação de duas vias real (onde

qualquer um dos lados pode enviar dados quando desejar), pois as comunicações com o servidor ainda

acontecem sobre HTTP, e portanto, o servidor não consegue iniciar um envio de dados, apenas pode

responder a requisições efetuadas pelo cliente. (Coach K. Wei, 2005)

De modo a simular uma comunicação de duas vias, as aplicações cliente frequentemente

utilizam-se de uma técnica denominada polling, que consiste no envio periódico de requisições para o

servidor para permitir que ele envie novas informações, caso existam. Desta maneira, pode-se simular

uma conexão de duas vias já que, do ponto de vista do usuário, novas informações aparecem sem que ele

tenha que explicitamente fazer uma nova requisição por elas. Esta solução, entretanto, não é eficiente em

termos de recursos computacionais, uma vez que serão realizadas inúmeras requisições inúteis, quando o

servidor ainda não tiver novas informações para responder. Também não representa uma via de

comunicação de tempo real, já que quando houver nova informação no servidor, ela só irá mostrar-se

para o usuário depois de decorrido o intervalo até a próxima requisição periódica da aplicação cliente.

Outra técnica também utilizada no propósito de tornar a web mais dinâmica, é um conceito que

recebe o nome de Comet, que engloba um conjunto de soluções que são tecnicamente diferentes mas

conceitualmente semelhantes. Seu princípio de funcionamento baseia-se em efetuar uma requisição

HTTP para o servidor, e, ao receber a resposta, nenhum dos lados encerra a conexão, mantendo-a aberta

para que o servidor possa enviar os eventos subsequentes dentro da mesma conexão, sem precisar

aguardar que o cliente faça uma nova requisição.

Esta técnica é principalmente utilizada em conjunto com as tecnologias que formam o Ajax,

apenas substituindo o mecanismo de polling por este mecanismo de conexão longa.

4

Os mecanismos para a utilização de Comet podem englobar diferentes tecnologias, as principais

são a utilização de um Iframe oculto na página, implicitamente declarado com tamanho infinito, que

ficaria em estado “carregando” indefinidadamente, por onde o servidor enviaria seus dados, ou utilizando

uma técnica denominada long-polling, que consiste em uma variação do conceito de polling, porém cada

requisição efetuada pelo cliente é mantida aberta até que o servidor tenha alguma informação para enviar,

após isto, a conexão é encerrada e o cliente deve estabelecer uma nova conexão. A vantagem neste caso é

que não há requisições desperdiçadas enquanto o servidor não tem novas informações.

Estas soluções, apesar de representarem uma evolução sobre o modelo de polling comum, ainda

apresentam problemas. No caso do Iframe oculto, não existe maneira de saber o estado atual do objeto,

nem existe um método para realizar tratamento de erros, além de ser uma distorção em relação ao

objetivo da utilização de Iframes. A técnica de long-polling ainda requer o estabelecimento de múltiplas

conexões e a troca de cabeçalhos HTTP, portanto perdendo no que tange a eficiência computacional.

(Anthony T. Holdener III, 2008)

4.4 Websocket

O Websocket é um protocolo que provê um canal de comunicação de duas vias entre um agente

de usuário e um host remoto, cujo objetivo é prover um mecanismo para aplicações web que necessitam

de comunicação bidirecional sem ter que depender da abertura de múltiplas conexões HTTP (p. ex.

Usando XMLHttpRequest ou long polling). (Hickson, 2010)

Foi desenvolvido com o princípio de que deve existir apenas um enquadramento (framing)

mínimo, de modo a economizar recursos e simplificar as implementações. É esperado que um

subprotocolo seja utilizado sobre o Websocket pela camada de aplicação, da mesma forma que o HTTP é

utilizado sobre o TCP.

Tecnicamente, o Websocket é apenas uma camada sobre o TCP que adiciona um modelo de

segurança web baseado em origem, um esquema de nomes e endereçamento (para suportar múltiplos

serviços em uma mesma porta e múltiplos nomes de host em um mesmo endereço IP), encapsula um

simples mecanismo de enquadramento e reimplementa o handshake de fechamento. Nada além disto. A

intenção é torná-lo o mais próximo possível do TCP puro, mas levando em conta os requerimentos da

web. Também é desenvolvido de forma tal que, pelo fato de o handshake possuir um cabeçalho HTTP

válido, possa dividir uma mesma mesma porta com servidores HTTP. (Hickson, 2010)

O protocolo consiste de um handshake inicial seguido da tranferência dos dados propriamente

dita.

Caso o handshake tenha sucesso, é inciada a transferência de dados. Sendo este um canal de

comuncação de duas vias, cada lado da conexão pode enviar dados a qualquer momento, diferentemente

do HTTP, onde o servidor não consegue enviar dados para o cliente no momento em que desejar,

precisando aguardar que o cliente faça uma requisição para que só então ele consiga transmitir qualquer

informação para o cliente.

Os dados são transmitidos na forma de texto codificado em UTF-8. Cada quadro (frame) de

dados inicia com um byte 0x00 e termina com um byte 0xFF, contendo o texto UTF-8 no meio. O

Websocket provê este enquadramento para que as implementações do protocolo possam expor tais

conexões utilizando um modelo baseado em eventos, ao invés de requerer a utilização de buffering e

agrupamento manual de mensagens. (Hickson, 2010)

Para encerrar uma conexão, um quadro consistido apenas por um byte 0xFF seguindo por um

byte 0x00 é enviado por um par (peer) para pedir que o outro encerre a conexão. O outro par então envia

um quadro idêntico, que indicando que a conexão pode ser encerrada. (Hickson, 2010)

5

Campos adicionais são usados para selecionar opções do protocolo Websocket. Na versão atual,

os campos adicionais suportados são “Cookie”, que pode ser utilizado para enviar cookies para o servidor

(p. ex. como mecanismo de autenticação) e “Sec-WebSocket-Protocol”, que contém uma string arbitrária

que descreve o subprotocolo (o protocolo da aplicação utilizado sobre o Websocket) que o cliente

pretende utilizar. O servidor ecoa este campo na sua resposta para indicar que ele suporta este

subprotocolo especificado.

Os outros campos do handshake são todos relativos à segurança. O campo “Host” serve como

proteção contra adulteração de DNS e para permitir que múltiplos domínios sejam atendidos em um

mesmo endereço. O campo “Origin” é usado para proteger o servidor contra acesso cruzado não

autorizado. O servidor especifica de qual origem ele está disposto a receber conexões incluindo um

campo “Sec-WebSocket-Origin” informando esta origem. Se múltiplas origens forem aceitas, o servidor

apenas ecoa o valor do campo “Origin” presente na requisição do cliente.

A figura 2 ilustra o funcionamento do handshake enviado pelo cliente:

GET /demo HTTP/1.1

Upgrade: WebSocket

Connection: Upgrade

Origin: http://exemplo.com

Host: exemplo.com

Sec-WebSocket-Key2: 12998 5 Y3 1 .P00

Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5

Sec-WebSocket-Protocol: teste

^n:ds[4U

Figura 2: handshake Websocket enviado pelo cliente para estabelecer uma conexão com um servidor

Por fim, o servidor deve provar ao cliente que ele recebeu o seu handshake (de maneira a evitar

que um servidor aceite conexões que não são uma conexão Websocket). Para fazê-lo, o servidor deve

pegar três peças de informação e combiná-las para formar uma resposta. As primeiras duas informações

vêm dos campos “Sec-WebSocket-Key1” e “Sec-WebSocket-Key2” do handshake do cliente. Para cada

um destes campos, o servidor deve retirar apenas os números, e então dividir este número formado pelo

número de caracteres de espaço contidos no campo. Estes dois números resultantes são então utilizados

no handshake do servidor. A terceira informação são os últimos 8 bytes do handshake, após todos os

campos. Ela é concatenada com os dois números resultantes obtidos anteriormente, formando uma string

de 128 bits cuja soma MD5 é usada pelo servidor para provar que ele leu o handshake.

A figura 3 ilustra o handshake do servidor:

6

HTTP/1.1 101 WebSocket Protocol Handshake

Upgrade: WebSocket

Connection: Upgrade

Sec-WebSocket-Origin: http://exemplo.com

Sec-WebSocket-Location: ws://exemplo.com/demo

Sec-WebSocket-Protocol: teste

8jKS'y:G*Co,Wxa-

Figura 3: Exemplo do handshake Websocket por parte do servidor.

A primeira linha é uma linha de status padrão HTTP, contendo sempre o status 101 (os outros

campos desta linha não são importantes).

As duas linhas seguintes são apenas para compatibilidade com o HTTP.

A quarta e quinta linhas fazem parte do modelo de segurança descrito acima, a primeira ecoando

o host e a segunda especificando exatamente o host, porta e nome do recurso Websocket.

A sexta linha é o campo de opção Websocket, que indica qual o subprotocolo que o servidor irá

utilizar (o cliente deve verificar se este valor é o mesmo enviado por ele durante o seu handshake)

Após os campos, é enviada a supracitada soma MD5. Se este valor não corresponder o que o

cliente espera, ele irá efetuar a desconexão.

Uma vez estabelecida a conexão, não é mais necessário utilizar estes cabeçalhos a cada pacote

enviado, apenas o esquema de enquadramento descrito anteriormente, constutuído simplesmente por um

byte 0x00 no início e um byte 0xFF ao final do pacote.

Percebe-se, portanto, que o Websocket visa solucionar o problema da comuncação bidirecional

em tempo real ao prover um método de conexão permanente que permite o tráfego em duas vias (full

duplex), iniciado a partir de uma conexão HTTP, e portanto capaz de funcionar normalmente utilizando a

estrutura já presente na web, como roteadores, balanceadores de carga e proxies. E, por dispensar a

utilização dos cabeçalhos HTTP uma vez que é estabelecida a conexão, e no lugar deles utilizar um

simples enquadramento de dois bytes, mostra-se também mais eficiente no que tange a utilização dos

recursos computacionais.

4.4.1 Aplicações para Websockets

As aplicações que mais poderiam se beneficiar da implementação de Websockets num primeiro

momento, são as que envolvem comunicações. O Gmail, um dos protagonistas no ramo de clientes de

email web, que hoje utiliza técnicas de polling para determinar quando o usuário recebeu novas

mensagens, teria grandes vantagens utilizando um sistema com Websockets, pois poderia oferecer maior

interatividade com mais eficiência de recursos. Poderia até mesmo aproveitar a mesma conexão para o

cliente de Gtalk integrado, que atualmente utiliza técnicas de Comet (Alex Russell, 2006), através de

uma conexão diferente da que o cliente de email utiliza (já que cada um deles, na verdade, utiliza

múltiplas conexões), economizando assim ainda mais recursos ao mesmo tempo que aumenta o

dinamismo proporcionado ao usuário, além de simplificar a implementação.

O Websocket também permitirá a criação de uma nova geração de serviços web interativos, como

o acompanhamento em tempo real de mercados, valores de câmbio e bolsas de valores. Este tipo de

7

aplicações precisam hoje utilizar complexos sistemas próprios para atender suas necessidades de curta

latência, e por isso seriam altamente beneficiados ao poderem utilizar um protocolo web, padronizado e

com implementações livres e facilmente disponíveis, sem abrir mão dos seus requisitos. Sistemas de

monitoramento também seriam beneficiados ao poder exibir alertas na tela em tempo real sem sobrecarca

excessiva nos servidores.

Além disso, o Websocket também poderá proporcionar vantagens a inúmeros sistemas que

utilizam Webservices (que consiste na interação entre sistemas computacionais utilizando protocolos

web), que passarão a poder utilizar uma única conexão permanente para a comunicação, além de passar a

permitir que, uma vez estabelecida a conexão, qualquer um dos lados envie informações a qualquer

momento, além de eliminar a necessidade de trafegar os cabeçalhos HTTP a cada requisição e resposta

efetuadas.

5 PROPOSTA DE SOLUÇÃO

A proposta deste trabalho é a implementação de um módulo (biblioteca), implementando as

funções de servidor Websocket e as de cliente, cada um em sua respectiva classe, que podem ser

utilizadas individualmente dependendo da finalidade do sistema em questão (cliente ou servidor). O

objetivo é criar um módulo simples, que implemente o protocolo e proveja uma API (Aplication

Programming Interface - Interface de Programação de Aplicação) simples e genérica para ser utilizada

com facilidade por outros sistemas, além de ser licenciado sob uma licensa livre, o que permite que

qualquer tipo de sistema se beneficie das vantagens desta nova tecnologia sem necessidade de

desenvolvimento próprio ou de pesados investimentos financeiros em soluções proprietárias.

5.1 Licença

Todo o código produzido neste trabalho está licenciado sob uma licença livre e open-source,

reconhecida pela Open Source Initiative e amplamente utilizada em projetos de software livre pelo

mundo.

A licença escolhida foi a MIT License, por sua simplicidade (possui apenas uma cláusula) e sua

permissividade (não limita a utilização sob nenhum aspecto). Com esta licença, são permitidos quaisquer

tipos de utilização do código, modificação, redistribuição e incorporação em outros projetos, livres ou

proprietários, com a única exigência de que, no trecho de código utilizado, seja mantida a nota de

copyright original e o trecho com clausula única da licença. A referência para o texto da licença pode ser

encontrada na seção correspondente do site da Open Source Initiative, em

http://www.opensource.org/licenses/MIT.

5.2 Modelagem e Metodologia

Os módulos criados são implementados na linguagem Python, constituindo o que se chama de

módulo python, cujo funcionamento é semelhante ao de uma biblioteca comum, entretanto para

programas escritos em Python.

5.2.1 API

O módulo implementa uma interface (API) baseada, dentro do possível - levando em

consideração as diferenças em cada linguagem – na API que é especificada para o Javascript pelo W3C

no HTML5 (em http://dev.w3.org/html5/websockets), de modo a manter uma certa compatibilidade com

outras implementações e simplificar o desenvolvimento.

Portanto, segundo a especificação, a classe do cliente implementa o objeto WebSocket, que

contém:

8

Construtor: o construtor (função executada quando o objeto é criado) do objeto WebSocket

recebe os parâmetros url e protocol, que são strings que representam a URL (servidor, caminho

e, opcionalmente, porta) e o subprotocolo utilizado, respectivamente. Recebe também,

opcionalmente, como parâmetro, funções que serão executadas em circunstâncias específicas

dentro do funcionamento do programa. São elas, nesta ordem:

◦ onopen: executada quando a conexão for estabelecida. Recebe como parâmetro o objeto

WebSocket criado (para que, caso desejado, possa chamar os métodos de envio de dados ou

encerramento da conexão)

◦ onmessage: executada quando uma mensagem for recebida. Recebe como parâmetro o

objeto WebSocket e uma string UTF-8 contendo os dados recebidos.

◦ onerror: executada quando ocorrer algum erro. Recebe como parâmetro o objeto

WebSocket e a conexão socket estabelecida com o servidor (para que medidas possam ser

tomadas caso os métodos de acesso via Websocket tenham falhado)

◦ onclose: executada quando a conexão for encerrada. Não recebe parâmetros.

Atributo readyState: informa o estado da conexão. Se contiver o valor 0, indica que a conexão

ainda está por ser estabelecida. O valor 1 indica que a conexão está estabelecida e a

comunicação é possível. O valor 2 indica que a conexão está sendo ecerrada e o valor 3 indica

que a conexão já foi encerrada ou não pôde ser estabelecida.

Método send: utilizado para enviar os dados desejados para o servidor. Recebe por parâmetro os

dados na forma de string codificada em UTF-8.

Método close: encerra a conexão Websocket.

A interface da classe do servidor é semelhante à do módulo cliente, com diferenças apenas no

construtor:

Construtor: o construtor (função executada quando o objeto é criado) do servidor WebSocket

recebe os parâmetros connection e port, que são, respectivamente, uma conexão via socket já

estabelecida com um cliente (os métodos para estabelecer esta conexão com o cliente através de

sockets são comuns e já existentes na linguagem) e a porta na qual o servidor está trabalhando

(necessário no handshake). Recebe também, opcionalmente, como parâmetro, funções que

serão executadas em circunstâncias específicas dentro do funcionamento do programa. São elas:

◦ onopen: executada quando a conexão for estabelecida. Recebe como parâmetro o objeto

WebSocket criado (para que, caso desejado, possa chamar os métodos de envio de dados ou

encerramento da conexão)

◦ onmessage: executada quando uma mensagem for recebida. Recebe como parâmetro o

objeto WebSocket e uma string UTF-8 contendo os dados recebidos.

◦ onerror: executada quando ocorrer algum erro. Recebe como parâmetro o objeto

WebSocket e a conexão socket estabelecida com o cliente (para que medidas possam ser

tomadas caso os métodos de acesso via Websocket tenham falhado)

◦ onclose: executada quando a conexão for encerrada. Não recebe parâmetros.

Atributo readyState: informa o estado da conexão. Se contiver o valor 0, indica que a conexão

ainda está por ser estabelecida. O valor 1 indica que a conexão está estabelecida e a

9

comunicação é possível. O valor 2 indica que a conexão está sendo ecerrada e o valor 3 indica

que a conexão já foi encerrada ou não pôde ser estabelecida.

Método send: utilizado para enviar dados para o cliente. Recebe por parâmetro os dados na

forma de string codificada em UTF-8.

Método close: encerra a conexão Websocket.

5.2.2 Demonstração de implementação de um cliente Websocket

A biblioteca de cliente Websocket produzida ao longo deste trabalho pode ser facilmente

utilizada por qualquer programa desenvolvido através da linguagem Python.

Para isto, deve-se primeiramente importar a classe WebsocketClient do módulo libwebsocket,

como mostra a figura 4:

from libwebsocket import WebsocketClient

Figura 4 – Importando a classe cliente do módulo libwebsocket

Com isto, na seção do programa onde se desejar iniciar a conexão Websocket com o servidor,

basta instanciar um novo objeto da classe WebsocketClient, observando que sejam passados os devidor

parâmetros para o construtor, conforma a seção 6.2 API especifica e a figura 5 exemplifica. O próprio

construtor da classe é quem estabelece a conexão com o servidor, o que significa que basta instanciar o

objeto e a conexão deverá ser estabelecida.

ws = WebsocketClient('ws://127.0.0.1:1234/teste', 'teste', None, onmessage, onerror, None)

Figura 5 – Instanciando o objeto WebsocketClient e efetuando a conexão

Observa-se que no exemplo da figura 5 acima, não foi especificado um método onopen e nem um

método onclose. Como foi dito na especificação da API, qualquer um deste métodos é opcional, e no

caso de não se desejar implementá-lo, basta passar um None em seu lugar (em Python, None é o mesmo

que o NULL presente em outras em outras linguagens).

Feito isto, pode-se opcionalmente verificar o estado do atributo readyState no objeto instanciado.

Se o valor for 1, a conexão foi estabelecida com sucesso.

Pode-se então envar dados para o servidor, bastando invocar o método send do objeto criado,

passando como parâmetro umas string UTF-8 representando os dados que se quer enviar.

Se houver uma resposta do servidor e um método onmessage tiver sido especificado, este método

será invocado e receberá como parâmetro, além do próprio objeto WebsocketClient, támbém uma string

UTF-8 representando a informação enviada pelo servidor.

Uma implementação completa de um cliente Websocket é exibida na figura 7. Este simples

programa apenas estabelece uma conexão Websocket com um servidor rodando na mesma máquina, na

porta TCP 1234. Envia então uma pequena mensagem para o servidor e aguarda uma resposta. Quando a

resposta é recebida, ela é exibida na tela e a conexão é encerrada.

10

5.2.3 Demonstração de implementação de um servidor Websocket

A biblioteca de servidor Websocket produzida ao longo deste trabalho, assim como a de cliente,

pode ser facilmente utilizada por qualquer programa desenvolvido através da linguagem Python. Para

fins didáticos, o servidor que será demonstrado neste capítulo não utilizará threads, o que significa que

ele não conseguirá atender a mais de um cliente simultâneo. Contudo, as instruções para que se crie um

servidor deste tipo não são específicas para a utilização de Websockets e podem ser facilmente

encontradas nas documentações apropriadas.

Primeiramente, deve-se importar a classe WebsocketServer do módulo libwebsocket, como

mostra a figura 6:

from libwebsocket import WebsocketServer

Figura 6 – Importando a classe servidor do módulo libwebsocket

import sys

from libwebsocket import WebsocketClient

def onopen(ws):

print "conexao estabelecida"

def onmessage(ws, data):

print "mensagem recebida:"

print data

ws.close()

def onerror(ws, conn):

print "erro. encerrando conexao"

ws.readyState = 3

conn.close()

sys.exit(1)

def onclose ():

print "conexao encerrada"

if __name__=='__main__':

ws = WebsocketClient('ws://127.0.0.1:1234/teste', 'teste', onopen, onmessage, onerror, onclose)

ws.send('teste msg')

while ws.readyState == 1:

pass

Figura 7 – Exemplo de programa cliente Websocket

11

Agora, deve-se abrir um socket TCP, e colocá-lo em bind na interface e porta desejadas. Em

seguida, deixa-se o socket em listen, indicando que ele está pronto para receber conexões. Depois disto,

invoca-se o método accept, que ficará esperando até que um cliente se conecte a este servidor e retornará

um novo socket através do qual se pode mandar e receber dados com o cliente, além do endereço deste

cliente. Este procedimento é exibido na figura 8:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.bind(('', 1234))

s.listen(1)

conn, cli_addr = s.accept()

Figura 8 – Preparando a conexão com o cliente

Após isto, quando o método accept retornar, tem-se um cliente conectado ao socket do servidor.

O que significa que está na hora de invocar o servidor Websocket. Para isto, basta instanciar um objeto

da classe WebsocketServer, passando os parâmetros conforme especifica a seção 5.2.1 API e

exemplificado pela figura 9:

ws = WebsocketServer(conn, 1234, onopen, onmessage, onerror, onclose)

Figura 9 – Criando o servidor Websocket

Após isto, pode-se opcionalmente verificar se o atributo readyState possui o valor 1, o que

significa que a conexão Websocket foi estabelecida com sucesso.

Neste ponto já tem-se uma conexão Websocket estabelecida com o cliente. Já pode-se, então,

enviar dados a qualquer momento invocando o método send. Toda informação que for recebida do cliente

será passada para o método onmessage, caso ele tenha sido passado adequadamente como parâmetro para

o construtor do servidor Websocket.

Uma implementação funcional de demonstração do servidor Websocket é exibida na figura 10.

Este programa extremamente simples apenas abre um servidor na porta 1234, e quando a conexão

Websocket é estabelecida, aguarda por uma mensagem do cliente, que, ao ser recebida, é exibida na tela

e uma resposta é enviada de volta ao cliente. Após isto, o servidor aguarda o encerramento da conexão

por parte do cliente.

Novamente, é importante ressaltar que a implementação dos métodos onopen, onmessage, onerror e

onclose é completamente opcional. No caso de algum destes métodos não ser implementado, basta passar

como parâmetro um None para o construtor do objeto Websocket. Vale notar, entretanto, que se um

método onmessage não for especificado, nenhum dado será recebido do cliente.

12

import socket

from libwebsocket import WebsocketServer

def onopen(ws):

print "conexao estabelecida"

def onmessage(ws, data):

print "mensagem recebida:"

print data

ws.send('resposta teste')

def onerror(ws, conn):

print "erro. encerrando conexao"

ws.readyState = 3

conn.close()

def onclose():

print "conexao encerrada"

if __name__=='__main__':

port = 1234

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.bind(('', port))

s.listen(1)

conn, cli_addr = s.accept()

server = WebsocketServer(conn, port, onopen, onmessage, onerror, onclose)

Figura 10 – Exemplo de programa servidor Websocket

6 TESTES E COMPARATIVOS

Já que o principal concorrente do Websocket, tecnologicamente falando, é o próprio HTTP, os

testes foram realizados no intuito de promover uma comparação entre estes dois.

Há duas modalidades básicas de testes. O primeiro é uma troca de mensagens (aqui chamadas

desta forma, mas que, na prática, podem ser qualquer coisa, até mesmo o conteúdo de arquivos) de

maneira síncrona, ou seja, o cliente envia uma requisição e aguarda a resposta do servidor. Este é o modo

de operação clássico do HTTP e serve para comparar o Websocket em um cenário de utilização simples e

comum (que não é exatamente o ambiente para o qual ele foi projetado e não tira proveito das facilidades

que este novo protocolo pode oferecer).

O segundo cenário é uma troca de mensagens assíncronas entre cliente e servidor, ou seja, o

cliente efetua uma requisição, mas o servidor não possui aquele recurso disponível naquele momento (na

prática, poderia ser uma operação ainda não concluída, ou, em um caso mais específico, uma verificação

por novos e-mails que podem chegar a qualquer momento para o usuário no servidor). Este cenário é

mais próximo do ambiente para o qual o Websocket foi criado, e deve tirar vantagens do novo paradigma

de comunicação por ele proposto. O HTTP, neste caso, precisa ficar fazendo constantes requisições para

o servidor para verificar se o recurso já está disponível (o teste foi executado com diferentes intervalos

entre estas requisições), enquanto que o Websocket faz a primeira requisição e apenas aguarda o retorno

do servidor quando o recurso solicitado estiver disponível.

13

O ambiente onde estes testes foram executados consiste de duas máquinas virtuais utilizando o

virtualizador Virtualbox, funcionando em uma mesma máquina física. Cada uma destas máquinas

virtuais roda o sistema operacional Fedora Linux 15. O sistema foi instalado apenas com os componentes

mais básicos necessários e não rodavam nenhum tipo de serviço adicional durante os testes.

Para a medição de tráfego, utilizou-se o utilitário Etherape, que é livre e amplamente disponível.

Para a medição de outras métricas (tempo, requisições), foram construídas medições dentro dos próprios

scripts de teste.

6.1 Comparativo com troca de mensagens síncronas

Neste teste é comparado o desempenho de cada um dos protocolos no método de utilização

clássico do HTTP, uma requisição de recurso é enviada para o servidor e imediatamente uma resposta é

retornada para o cliente. Este procedimento é executado dez vezes, em sequência imediata. Deve-se

notar, antes de tudo, que este não é o cenário para o qual o Websocket foi desenvolvido. Ele foi

desenvolvido para operar assincronamente e possibilitar que o servidor possa enviar dados a qualquer

momento sem depender de uma requisição imediata do cliente. Ainda assim, os testes foram realizados

para analisar o comportamento do Websocket em um ambiente web clássico.

Neste teste, foram medidos o número de pacotes TCP trafegados, o número de bytes trafegados, e

o tempo de execução do cliente.

Os resultados estão exibidos nos gráficos representados abaixo pelas figuras 11, 12 e 13.

Figura 11 – Número total de pacotes trafegados (ambos o sentidos)

14

Figura 12 – Quantidade total de bytes trafegados (nos dois sentidos)

Aqui podemos começar a perceber uma vantagem do Websocket. Apesar do número de

requisições e respostas ter sido o mesmo nos dois protocolos (devido à natureza do teste, foram dez

requisições e dez respostas), o tráfego de rede foi consideravelmente melhor quando se utilizou

Websockets. Isto pode ser explicado pelo fato de o Websocket não precisar trafegar os cabeçalhos em

todas as requisições e respostas: eles são trocados apenas no estabelecimento da conexão, e, após isto, as

informações podem ser trocadas livremente entre os dois lados.

Figura 13 – Tempo de execução do cliente

Na figura 13, vê-se a desvantagem do Websocket com relação ao HTTP neste cenário de

execução. Como viu-se anteriormente, o handshake mínimo do HTTP é extremamente simples, se

comparado ao relativamente complexo do Websocket. Isto porque no Websocket a troca de cabeçalhos

15

no início da conexão tem diversas medidas de segurança, para evitar que a conexão seja estabelecida com

um host cuja implementação do protocolo seja incompatível, ou até mesmo que a conexão sofra um

ataque de interceptação.

Isto faz com que a abertura da conexão no Websocket seja mais demorada, e por isto o tempo

total de execução do cliente também acaba sendo maior.

Quando da consideração acerca da utilização do Websocket em um cenário como o descrito neste

teste, deve-se avaliar o tempo médio previsto para a duração de cada conexão: se forem conexões

relativamente longas e duradouras, o Websocket pode ser considerado uma alternativa válida, pois a

pequena diferença de tempo durante o estabelecimento da conexão pode ser facilmente dissolvida

durante toda a duração desta, e aí o menor tráfego de rede apresentado pelo Websocket pode representar

uma vantagem definitiva. No entanto, se a previsão forem conexões pequenas e muito curtas,

provavelmente o Websocket não seja a melhor escolha para este cenário, pois o maior tempo durante o

estabelecimento da conexão pode fazer uma grande diferença se a duração destas conexões for muito

curta.

6.2 Comparativo com troca de mensagens assíncronas

Neste teste, é simulado o funcionamento de um serviço de notícias: no servidor, notícias novas

chegam em intervalos aleatórios, à medida que fatos acontecem e as manchetes vão sendo publicadas

pela operadora do serviço. Do outro lado, existe um cliente interessado em acompanhar estas notícias.

Ele deve se conectar ao servidor e buscar qualquer notícia nova que este possua. Este é um ambiente

favorável ao Websocket pois o seu funcionamento é basicamente assíncrono.

Para a finalidade dos testes, o serviço simulado rodou por 20 minutos, e novas notícias eram

inseridas no servidor em um intervalo randômico de 110 a 130 segundos.

Para cada um dos testes, foram medidos os pacotes TCP trafegados (o número apresentado é a

quantidade trafegada em ambos os sentidos), os bytes trafegados (também a quantidade total), o número

de requisições enviadas pelo cliente (que influencia diretamente nos dois gráficos anteriores) e o tempo

da atualização, ou seja, o delay do cliente, que significa quanto tempo decorreu entre o servidor ter uma

nova notícia e o cliente receber esta atualização. Todos os resultados apresentados são uma média do

total do teste dividido pelo número de notícias, para dar uma visão individual do resultado.

Como o HTTP necessita utilizar método de polling para este perfil de serviço, o teste foi

executado com três configurações distintas de intervalos entre as requisições, a saber, 5, 10 e 30

segundos.

Os resultados estão exibidos nos gráficos representados abaixo pelas figuras 14, 15, 16 e 17.

16

Figura 14 – Quantidade de pacotes trafegados em média por notícia

Figura 15 – Quantidade de bytes trafegados em média por notícia

17

Figura 16 – Quantidade de requisições feitas pelo cliente por notícia em média

Observa-se a clara vantagem do Websocket nestes resultados, ainda maior que no teste síncrono

realizado anteriormente. Isto porque o Websocket não precisa realizar polling, ele envia apenas uma

requisição de nova notícia para o servidor, e quando o servidor receber uma notícia nova, este irá

responder para o cliente com a atualização solicitada.

Figura 17 – Tempo médio para o cliente receber uma nova notícia

Neste último gráfico pode-se ver a maior vantagem do Websocket quando se trata de

comunicação assíncrona. O tempo entre a nova notícia estar disponível no servidor e o cliente recebê-la é

praticamente nulo, e é proporcionalmente tão pequeno ao lado dos delays do HTTP que sequer aparece

no gráfico como uma barra.

18

Observa-se nestes gráficos também o clássico dilema do método polling: quanto menor o

intervalo entre cada requisição, menor o delay, mas maior o tráfego de rede (mais requisições são feitas).

Quanto maior o intervalo, menor o tráfego de rede (menos requisições), mas o tempo para que o cliente

perceba a disponibilidade do recurso solicitado aumenta significativamente.

7 CONCLUSÕES

Através deste trabalho, criou-se uma implementação simples, genérica e funcional do protocolo

Websocket, tanto de cliente como de servidor.

Através desta implementação, puderam ser realizados testes que comprovam a viabilidade do

Websocket como protocolo web, que mostrou ser uma alternativa vantajosa ao HTTP, principalmente em

ambientes assíncronos, onde atualmente o HTTP necessita utilizar-se de técnicas de polling, que o

tornam bastante ineficiente nesta função. O protocolo Websocket neste mesmo ambiente mostrou-se

muitas vezes mais econômico em termos de recursos de rede, além de prover a resposta para o cliente

quase que instantâneamente. Com HTTP, através de polling, a resposta demora vários segundos para

efetivamente chegar até o cliente desde o momento em que o servidor tem o recurso disponível.

Além de apresentar vantagens nas áreas hoje cobertas pelo HTTP, o Websocket permite a criação

de uma nova gama de serviços via web com funcionalidades que simplesmente não são possíveis de se

conseguir via HTTP, onde qualquer um dos lados pode enviar dados a qualquer momento, aumentando a

interatividade significativamente e diminuindo delays.

No modelo de utilização tradicional de requisição-resposta, o Websocket mostrou ser uma

alternativa viável, vantajosa em alguns casos por ser mais eficiente quanto ao tráfego de rede. Contudo,

devido ao maior tempo necessário para o estabelecimento da conexão, dependendo do perfil da aplicação

a ser considerada, o Websocket pode se tornar a alternativa menos vantajosa com relação ao HTTP, caso

o perfil de funcionamento da aplicação em questão envolva um número grande de conexões curtas (por

exemplo, uma nova conexão é estabelecida e apenas uma requisição trafega por ela, quando ela então é

encerrada e a próxima requisição precisa abrir uma nova conexão).

Este trabalho atingiu seu objetivo ao fornecer uma implementação funcional do protocolo

Websocket, disponível livremente, que pode ser facilmente utilizada em qualquer sistema desenvolvido

em Python. Além disso, pode servir como base ou referência para facilitar a implementação de

Websockets em outras linguagens.

As oportunidades que o Websocket abre para a utilização de protocolos web são bastante amplas.

Pode ser implementado na comunicação entre sistemas das mais diversas aplicações (no modelo de

webservices) pois são conexões que tendem a durar bastante tempo (a não ser que a conectividade entre

os nodos seja interrompida, o que é relativamente raro) possibilitando uma comunicação mais rápida e

eficiente. Em termos de aplicações que interagem diretamente com o usuário, a gama de possibilidades

também é variada. Pode-se imaginar diversos sistemas que hoje utilizam HTTP cuja interatividade

poderia ser melhorada na utilização de Websockets. Por exemplo, o acompanhamento de uma partida de

futebol em um site de esportes, ou as manchetes importantes em um site de notícias, poderiam estar

sendo fornecidas em tempo real para o usuário, sem que este precise atualizar a página manualmente, e

sem ter de utilizar ineficientes métodos de polling com HTTP. É possível ainda imaginar novos tipos de

aplicações, por exemplo, um site de busca na web onde, após digitada uma busca, não se tenha uma lista

de resultados estáticos, mas um fluxo em tempo real à medida que novas atualizações sobre o assunto

buscado forem sendo realizadas.

Outras oportunidades também existem em ramos onde hoje não são utilizados protocolos web,

devido à necessidade de baixo tempo de resposta, como o acompanhamento de mercados de câmbio e de

19

ações. Os home brokers disponibilizados pelas operadoras de investimentos hoje precisam ser complexas

aplicações desenvolvidas a partir do zero, tanto o cliente como o servidor, pois é necessário implementar

um protocolo próprio sobre TCP para que se consiga o baixo tempo de resposta necessário neste tipo de

aplicação. Com a utilização de Websocket este sistema seria drasticamente simplificado, pois poder ia-se

então utilizar um protocolo web, que já possui implementações de servidor (servidores web) e cliente

(navegadores) prontas, além de poder disponibilizar isto diretamente em seu site, tornando a utilização

mais simples e fácil. Tudo isto sem abrir mão da eficiência e interatividade.

O que não foi avaliado neste trabalho, entretanto, e que deve ser avaliado antes de qualquer tipo

de migração de serviço ou construção de um novo utilizando Websockets, é em termos de utilização dos

recursos do servidor. Pelos testes que foram executados percebe-se que o tráfego de rede é bastante

reduzido, contudo, outros recursos como memória e processamento devem ser estudados antes de uma

utilização em larga escala.

8 REFERÊNCIAS

RUSSEL, Alex. Comet: Low Latency Data for the Browser. Disponível em

http://alex.dojotoolkit.org/2006/03/comet-low-latency-data-for-the-browser. 2006.

HOLDENER III, Anthony T.. Ajax: The Definitive Guide. Editora O'Reilly. 2008.

BERNERS-LEE, Tim; FIELDING, R.; FRYSTYK, H. RFC 1945 - Hypertext Transfer Protocol --

HTTP/1.0. Disponível em http://www.ietf.org/rfc/rfc1945.txt. 1996.

WEI, Coach K. AJAX: Asynchronous Java + XML?. Disponível em

http://www.developer.com/design/article.php/10925_3526681_1/AJAX-Asynchronous-Java--XML.htm.

2005.

HICKSON, I. Editor's Draft - The WebSocket API. Disponível em

http://dev.w3.org/html5/websockets. 2010.

HICKSON, I. Internet-Draft - The Websocket Protocol. Disponível em http://tools.ietf.org/html/draft-

hixie-thewebsocketprotocol. 2010.

GARRET, Jesse James. Ajax: A New Approach to Web Applications. Disponível em

http://www.adaptivepath.com/ideas/essays/archives/000385.php. 2005.

FUJISHIMA, Yuzo; UKAI, Fumitoshi; YOSHIMO Takeshi. Web Sockets Now Available In Google

Chrome. Disponível em http://blog.chromium.org/2009/12/web-sockets-now-available-in-google.html.

2009.