O que são Websockets?
Nos últimos anos, um novo tipo de comunicação começou a surgir na web e em aplicações móveis, chamadas websockets. Este protocolo foi há muito esperado e foi finalmente padronizado pela IETF em 2011, abrindo caminho para uma utilização generalizada.
Este novo protocolo abre uma linha de comunicação muito mais rápida e eficiente para o cliente. Tal como o HTTP, os websockets funcionam sobre uma ligação TCP, mas são muito mais rápidos porque não temos de abrir uma nova ligação para cada vez que queremos enviar uma mensagem, uma vez que a ligação é mantida viva durante o tempo que o servidor ou cliente quiser.
P>Even melhor, uma vez que a ligação nunca morre temos finalmente uma comunicação full-duplex disponível para nós, o que significa que podemos empurrar dados para o cliente em vez de termos de esperar que eles peçam dados ao servidor. Isto permite que os dados sejam comunicados para trás e para a frente, o que é ideal para coisas como aplicações de chat em tempo real, ou mesmo jogos.
Como funcionam os Websockets?
No seu núcleo, um Websocket é apenas uma ligação TCP que permite uma comunicação full-duplex, o que significa que um lado da ligação pode enviar dados para o outro, mesmo ao mesmo tempo.
Para estabelecer esta ligação, o protocolo inicia efectivamente o aperto de mão como um pedido HTTP normal, mas depois é “actualizado” usando o cabeçalho HTTP de pedido de actualização, como isto:
O servidor envia então uma resposta HTTP 101 “Switching Protocols”, reconhecendo que a ligação vai ser actualizada. Uma vez feita esta ligação, muda para um protocolo binário bidireccional, altura em que os dados da aplicação podem ser enviados.
Tudo o que o protocolo tem de fazer para manter a ligação aberta é enviar alguns pacotes ping/pong, o que diz ao outro lado que eles ainda lá estão. Para fechar a ligação, um simples pacote de “ligação fechada” é enviado.
alguns exemplos de Websocket
Das muitas bibliotecas de Websocket diferentes para Node.js disponíveis para nós, optei por usar socket.io ao longo deste artigo porque parece ser o mais popular e é, na minha opinião, o mais fácil de usar. Embora cada biblioteca tenha a sua própria API única, elas também têm muitas semelhanças, uma vez que estão todas construídas sobre o mesmo protocolo, por isso espero que consiga traduzir o código abaixo para qualquer biblioteca que queira utilizar.
Para o servidor HTTP, estarei a utilizar o Express, que é o servidor de Nodo mais popular por aí. Tenha em mente que também pode usar o módulo http simples se não precisar de todas as funcionalidades do Express. Embora, uma vez que a maioria das aplicações irá utilizar o Express, é o que também iremos utilizar.
Note: Ao longo destes exemplos removi grande parte do código da placa de caldeira, pelo que alguns deste código não irão funcionar fora da caixa. Na maioria dos casos pode referir-se ao primeiro exemplo para obter o código da chapa de caldeira.
Estabelecer a Ligação
Para que uma ligação seja estabelecida entre o cliente e o servidor, o servidor deve fazer duas coisas:
- Ligue-se ao servidor HTTP para tratar as ligações websocket
- Serve o
socket.io.js
biblioteca cliente como um recurso estático
No código abaixo, pode ver o item (1) a ser feito na 3ª linha. O item (2) é feito para si (por defeito) pelo socket.io
biblioteca e é servido no caminho https://stackabuse.com/socket.io/socket.io.js
. Por defeito, todas as ligações e recursos da web são servidos dentro do /socket.io
caminho.
Servidor
O cliente também precisa de fazer duas coisas:
- Carregar a biblioteca a partir do servidor
- Li> Chamada
.connect()
para o endereço do servidor e o caminho do websocket
Cliente
<script src="https://stackabuse.com/socket.io/socket.io.js"></script><script> var socket = io.connect('/');</script>
Se navegar no seu navegador para e inspeccionar os pedidos HTTP nos bastidores utilizando as ferramentas de desenvolvimento do seu navegador, deverá poder ver o aperto de mão a ser executado, incluindo os pedidos GET e a resposta resultante aos Protocolos de Comutação HTTP 101.
Enviar Dados do Servidor para o Cliente
Okay, agora para algumas das partes mais interessantes. Neste exemplo vamos mostrar-lhe a forma mais comum de enviar dados do servidor para o cliente. Neste caso, estaremos a enviar uma mensagem a um canal, que pode ser subscrito e recebido pelo cliente. Assim, por exemplo, uma aplicação cliente pode estar a ouvir no canal ‘anúncios’, que conteria notificações sobre eventos em todo o sistema, como quando um utilizador entra numa sala de chat.
p>No servidor, isto é feito esperando que a nova ligação seja estabelecida, depois chamando o métodosocket.emit()
para enviar uma mensagem a todos os clientes ligados.
Servidor
io.on('connection', function(socket) { socket.emit('announcements', { message: 'A new user has joined!' });});
Cliente
Enviar dados do cliente para o servidor
Mas o que faríamos quando quiséssemos enviar dados de outra forma, de cliente para servidor? É muito semelhante ao último exemplo, utilizando os métodos socket.emit()
e socket.on()
.
Servidor
Cliente
Contagem de Utilizadores Ligados
Este é um bom exemplo a aprender uma vez que mostra mais algumas características de socket.io
(como o disconnect
evento), é fácil de implementar, e é aplicável a muitos webapps. Vamos utilizar o connection
e disconnect
eventos para contar o número de utilizadores activos no nosso sítio, e vamos actualizar todos os utilizadores com a contagem actual.
Servidor
Cliente
Uma forma muito mais simples de rastrear a contagem de utilizadores no servidor seria simplesmente usar isto:
var numClients = io.sockets.clients().length;
Mas aparentemente existem alguns problemas em torno disto, pelo que poderá ter de se manter a par da contagem de clientes.
Rooms and Namespaces
As chances são à medida que a sua aplicação cresce em complexidade, necessitará de mais personalização com os seus websockets, como enviar mensagens a um utilizador específico ou conjunto de utilizadores. Ou talvez deseje uma separação rigorosa da lógica entre as diferentes partes da sua aplicação. É aqui que salas e namespaces entram para jogar.
Nota: Estas características não fazem parte do protocolo websocket, mas adicionadas no topo por socket.io
.
Por defeito, socket.io
utiliza o namespace raiz (/
) para enviar e receber dados. Programmaticamente, pode aceder a este namespace através de io.sockets
, embora muitos dos seus métodos tenham atalhos em io
. Assim, estas duas chamadas são equivalentes:
io.sockets.emit('stats', { data: 'some data' });io.emit('stats', { data: 'some data' });
Para criar o seu próprio namespace, tudo o que tem de fazer é o seguinte:
Também, o cliente tem de se ligar explicitamente ao seu namespace:
<script src="https://stackabuse.com/socket.io/socket.io.js"></script><script> var socket = io('/stackabuse');</script>
Agora quaisquer dados enviados dentro deste namespace serão separados do namespace padrão /
namespace, independentemente do canal utilizado.
indo ainda mais longe, dentro de cada espaço de nomes pode entrar e sair de ‘salas’. Estas salas proporcionam outra camada de separação no topo dos namespace, e uma vez que um cliente só pode ser adicionado a uma sala do lado do servidor, proporcionam também alguma segurança extra. Assim, se quiser ter a certeza de que os utilizadores não estão a bisbilhotar certos dados, pode usar uma sala para os esconder.
Para ser adicionado a uma sala, deve .join()
it:
io.on('connection', function(socket){ socket.join('private-message-room');});
Então, a partir daí pode enviar mensagens a todos os que pertencem à sala em questão:
io.to('private-message-room').emit('some event');
E finalmente, ligue .leave()
para deixar de receber mensagens de eventos de uma sala:
socket.leave('private-message-room');
Conclusion
Esta é apenas uma biblioteca que implementa o protocolo websockets, e há muitas mais lá fora, todas com as suas próprias características e pontos fortes únicos. Aconselho a experimentar algumas das outras (como por exemplo, os websockets com aceno de cabeça) para se ter uma ideia do que há por aí.
Em apenas algumas linhas, é possível criar algumas aplicações bastante poderosas, por isso estou curioso para ver o que se pode arranjar!
0 comentários