Executando verificação de segurança...
6

Socket.IO - Primeiros passos

Desde o início do desenvolvimento web, muitas pessoas desenvolvedoras enfretaram diversos impedimentos relacionados ao disparo de eventos. Antes mesmo dos diversos frameworks que gerenciam o estado das aplicações, as mesmas que agarravam apenas ao XMLHttpRequest para fazer requisições assíncronas às APIs próprias e de terceiros.

Entretanto, em algumas aplicações, queremos controlar estados e gerar nossos próprios eventos criando uma integração entre cliente e servidor que não necessita exclusivamente de uma API. Para isso, o Socket.IO pode nos ajudar muito.

Mas, o que é o Socket.IO?

O socket.IO é uma biblioteca que permite comunicação bidirecional e baseada em eventos entre um servidor e um cliente e o melhor, com baixa latência. Construído sobre o WebSocket, o mesmo permite reconexão e o envio de pacotes entre cliente e servidor com o menor custo para o seu servidor.

O socket.IO tem suporte para diversas linguagens:

  • Javascript
  • Java
  • Python
  • Golang
  • .NET
  • C++
  • Swift
  • Rust
  • Kotlin ...

Visto isso, vamos a uma pequena introdução utilizando Node.JS. O exemplo mais simples que temos para a utilização do socket.IO é a criação de uma sala de bate-papo. Isso porque temos uma aplicação de troca de mensagens entre diversos clientes em tempo real, cuja comunicação deve passar pelo servidor, seja apenas para gerenciamento ou para salvar em alguma base de dados.

Mas não precisamos salvar em uma base de dados para fornecer uma comunicação em tempo real. Temos apenas que criar uma comunicação baseada em eventos com o Socket.IO

Vamos ao código

Server-side

Primeiro, criamos um server http para o nosso back-end

// server.js
const http = require('http');
server = http.createServer(app); 

Depois, vamos criar um novo arquivo chamado Room.js, onde deixaremos todos os nossos eventos do socket.IO e vamos dizer ao nosso server que, ao se conectar, nossos eventos estarão sem gerenciados nesse arquivo.

// server.js
const io = require('socket.io')(server);
const Room = require('./Room')(io);
server.listen(port, () => console.log("Chat online"));

Podemos agora criar o arquivo Room.js para centralizar nossos eventos. E nesse momento, vamos começar a trabalhar de fato com o Socket.IO utilizando apenas dois métodos: on e emit.

O método on é o método que diz qual é o evento que você deseja receber e quais as informações e códigos relacionados ao mesmo. É basicamente o método que serve como sua caixa de entrada.

O método emit, ao contrário do on, é o método que dispara uma mensagem para algum evento e envia as informações. É basicamente o método que serve como caixa de saída.

Relacionando os dois métodos, você pode ter os dois tanto no lado cliente como no lado servidor e para exemplificar, se você tem no server-side o método on e no client-side o método emit, temos

// server-side
socket.on('mensagem', function(texto) {
    console.log(texto);
});
// client-side
socket.emit('mensagem', 'Olá pessoas desenvolvedoras do tabnews');

Isso quer dizer que no momento que disparássemos o código do cliente, seja por um botão ou qualquer outra interação qualquer, teríamos um print no back-end da mensagem Olá pessoas desenvolvedoras do tabnews

E como o socket.IO sabe onde direcionar?

Graças ao nome do evento, mensagem, que você escolheu. Enquanto nos métodos emit, temos como parâmetro o nome do evento e alguma informação, nos métodos on temos o mesmo nome de evento e uma função que receberá como parâmetro, todos os outros parâmetros restantes do método emit. Legal né?

.

Agora, alguns conhecimentos mais avançados. No socket.io, temos o conceito de salas. Na qual cada client pode ser direcionado a uma sala e as mensagens podem ser direcionadas tanto a uma sala como a algun cliente específico. Dessa forma, temos mais 03 métodos interessantes: join, leave e to.

O método join serve para direcionar um cliente a alguma sala. A construção do mesmo é apenas indicar qual o nome da sala. Então temos:

socket.join(nomeDaSala);

O método leave serve para fazer o oposto do método join, ou seja, tirar o cliente de alguma sala. Então temos:

socket.leave(nomeDaSala);

O método to, por último serve para enviar uma mensagem em determinada sala. Ele se une ao método emit mas garantindo que apenas os clientes associados à determinada sala recebam a mensagem. Então temos:

socket.to(nomeDaSala).emit('mensagem', 'Olá pessoas desenvolvedoras do tabnews');

O resto do funcionamento é o mesmo. Trazendo esse contexto para o nosso Room.js, temos o seguinte bloco de código

function listen(socket){
   const io = _io;
   
   socket.on('join', function(sala){
       socket.join(sala);
   });

   socket.on('leave', function(sala){
       socket.leave(sala);
   });

   socket.on('mensagem', function(Sala, Mensagem){
       socket.to(Sala).emit('msg', Mensagem);
   });
}

module.exports = function(io){
   _io = io;
   return {listen};
};

Client-side

Agora para o nosso lado cliente, temos basicamente, todos os mesmos eventos mas com construções inversas. Onde temos on de um lado, temos emit do outro.

 socket.on('msg', function(Mensagem){
     // Código relacionado a receber uma mensagem no cliente.
 });
 
 socket.emit("join",nomeDaSala);
 
 socket.emit("leave", nomeDaSala);
 

Repositório completo

Para facilitar na absorção, deixei um repositório pronto como uma sala básica de bate-papo com socket.IO. Não utilizei muitos frameworks e para ser absorvido, independentemente da tecnologia de front-end que você utiliza, deixei com JQuery que é mais simples de entender.

Bate-Papo

O repositório pode ser encontrado aqui.

O que mais posso fazer com Socket.IO

Apesar da sala de bate-papo ser o exemplo mais didático da utilização dessa biblioteca, podemos fazer inúmeras aplicações com Socket.IO

  • Jogos online
  • SIP Server (VoIP)
  • WebRTC ...

Inclusive, com o Socket.IO, podemos fazer uns clones funcionais bem interessantes, como o clone de softwares como:

  • Discord
  • Zoom
  • Twitch

Mas esses clones e a explicação de WebRTC, caso gostem desse conteúdo, deixamos para uma próxima.

Espero que gostem. Bons estudos

Carregando publicação patrocinada...
1

Obrigado pelo texto! É ótimo ver que o Socket.IO é uma biblioteca tão versátil e útil para a criação de aplicações em tempo real. Adorei o exemplo da sala de bate-papo, e é realmente incrível como podemos criar inúmeras outras aplicações com ele, como jogos online, servidores SIP e até mesmo clones de softwares populares. Obrigado por compartilhar seus conhecimentos sobre o Socket.IO!

Este comentário foi gerado por uma inteligência artificial. Para saber mais, leia esta publicação.

1
1

Cara, sem dúvidas o socket.io é incrivel, mas sempre acabo sofrendo com um problema: o reconnect. No meu caso sempre quando estou conectado em um ws e troco do wifi para 4g e vice-versa, falha em reconectar. Ja procurei a beça e sempre acabo no mesmo cenário, alguma dica?

1

Oi Alan. Tudo bem?

De fato, essa é uma dificuldade comum em quem já está desenvolvendo com socket.io

Por que isso ocorre?

Como a biblioteca funciona sobre websocket, o túnel de rede é criado. Ao iniciar um novo túnel, o socket.id é perdido e um novo é gerado criando o fluxo de join novamente

Como podemos resolver

Se a sua aplicação permitir, deixe um id gerado por você associado a uma página (pode ser algo aleatório ou informações de login, caso sua aplicação tenha controle de usuários). Quando você for realizar o seu join, salve no seu server alguma matriz multidimensional que relacione o socket.id com o seu id.

Em caso de queda, seja por refresh da página ou socket.disconect, você pode iniciar uma nova conexão e o socket.IO irá gerar um novo socket.id e caso esse socket.id não esteja relacionado com o seu id, você substitui na sua matriz e faz leave do id antigo e join no id novo

Em alguns trabalhos que já realizei com socket.io, no lado do cliente, eu garantia que a pessoa não duplicasse a página ou não realizasse login em outra máquina. Então, quando alguém logava com alguma conta já logada, a página anterior era desconectada automaticamente e redirecionava para a página de login.

Espero que ajude

1

E quanto a autenticação? JWT funciona? Cookies? Qual é o fornato correto?

E quanto a eventos dinâmicos? Qual o padrão para envio e recebimento de eventos com ids?

Ex.: quero ouvir um evento "msg:1234" relativo ao id da sala 1234. Poderia ter dezenas de salas diferentes e ouvir somente as que estou conectado ou pode acontecer de o servidor enviar mensagens para salas em que eu não estou ouvindo? Minha rede recebe mensgens que não deveria chegar para mim, mesmo que a interface não faça nada com ela? Isso ainda estará vagando pela rede de todo mundo?

1

Olá klawdyo. Tudo bem?

Sobre a autenticação, você terá de controlar manualmente. Seja por eventos ou controlando os usuários da sua aplicação. O envio de um token por JWT através dos sockets funciona sem problemas e você pode pegar o payload dos dois lados. Inclusive, os parâmetros de informação trafegadas não precisam ser texto, mas podem ser bytes. Se o próprio socket.IO tem uma autenticação dele? Não.

Sobre a eventos dinâmicos, criá-los não será para você a melhor prática, apesar de funcionar. No lado server, você tem conhecimento de todas as salas enquanto no lado client, você pode armazenar em qual sala aquele socket está em uma constante e mandar a sala como parâmetro para o server e o server consegue mandar para a sala com o to. Exemplo:

// server-side
socket.on('mensagem', function(Sala, Mensagem){
   socket.to(Sala).emit('mensagem', Mensagem);
});
// client-side
socket.on('mensagem', function(Mensagem){
  // código que trata do recebimento da mensagem
});

socket.emit('mensagem', 'minhaSala','minha Mensagem');

Para além disso, caso você tenha um evento personalizado para cada sala, você ficará limitado ao número de salas e não conseguirá fazer isso escalável e dinâmico. Por exemplo, se você tiver 500 salas, você não irá, no lado server, fazer o método on para 500 salas, apesar de no lado cliente, você conseguir fazer um emit para um evento com nome dinâmico. Caso queira fazer isso, mesmo assim, você pode usar o evento onAny no lado server. Esse evento dispara com qualquer evento recebido pelo socket.IO e tem como primeiro parâmetro, o nome do evento que foi lançado pelo emit no lado cliente.