WebSocket: como funciona a comunicação em tempo real

Entenda por que o HTTP tradicional não resolve chat, notificação instantânea e dashboard ao vivo, como o WebSocket resolve isso com uma conexão persistente e um exemplo prático de servidor e cliente em Node.


Toda vez que aparece um chat que atualiza sozinho, uma notificação que chega sem você recarregar a página, ou um dashboard com número mudando ao vivo, tem uma chance boa de existir um WebSocket por trás. É um assunto que aparece pouco no dia a dia de quem só trabalha com CRUD tradicional, mas que vira essencial assim que o projeto precisa de algo em tempo real.

O problema do HTTP tradicional

HTTP funciona no modelo pergunta e resposta. O cliente manda uma requisição, o servidor responde, e a conexão se encerra. Se você quer saber se chegou mensagem nova num chat, o jeito ingênuo é o cliente ficar perguntando de novo e de novo, de tempos em tempos:

setInterval(() => {
  fetch("/api/mensagens/novas").then((res) => res.json());
}, 2000);

Isso se chama polling, e funciona, mas é ineficiente. A cada 2 segundos, cada usuário aberto na página dispara uma requisição nova, a maioria delas respondendo "nada mudou". Multiplicando isso por milhares de usuários, é bastante trabalho de servidor gasto só pra dizer que não tem novidade.

WebSocket: uma conexão que fica aberta

O WebSocket resolve isso invertendo a lógica. Em vez do cliente ficar perguntando, ele abre uma conexão única com o servidor e essa conexão fica aberta, os dois lados podem mandar mensagem um pro outro a qualquer momento, sem precisar abrir uma requisição nova a cada vez.

A conexão começa como um HTTP normal, com um handshake especial (o header Upgrade: websocket), e depois desse aperto de mão inicial o protocolo muda: a mesma conexão TCP continua aberta, mas agora falando o protocolo WebSocket, não mais HTTP. É por isso que dá pra mandar dado dos dois lados a qualquer momento, sem o ciclo de pergunta e resposta.

Um exemplo prático com ws

A biblioteca ws é a forma mais direta de subir um servidor WebSocket em Node, sem framework por cima:

// servidor
import { WebSocketServer } from "ws";
 
const wss = new WebSocketServer({ port: 8080 });
 
wss.on("connection", (socket) => {
  console.log("cliente conectado");
 
  socket.on("message", (data) => {
    console.log("recebido:", data.toString());
 
    // devolve a mensagem pra todo mundo conectado
    wss.clients.forEach((cliente) => {
      cliente.send(`nova mensagem: ${data}`);
    });
  });
 
  socket.on("close", () => {
    console.log("cliente desconectou");
  });
});

Do lado do navegador, a API já vem nativa, sem precisar instalar nada:

// cliente
const socket = new WebSocket("ws://localhost:8080");
 
socket.onopen = () => {
  socket.send("olá, servidor");
};
 
socket.onmessage = (event) => {
  console.log("mensagem recebida:", event.data);
};

Repara que os dois lados escutam eventos (message, close, open), não fazem chamada e esperam resposta. É uma via de mão dupla o tempo todo, enquanto a conexão estiver aberta.

Quando vale a pena usar

WebSocket não é a ferramenta certa pra tudo. Ele resolve bem um problema específico: quando o servidor precisa iniciar o envio de dado, sem o cliente ter pedido primeiro. Chat, notificação em tempo real, colaboração ao vivo (tipo cursor de outra pessoa se movendo num documento), dashboard financeiro com preço mudando, jogo multiplayer simples.

Pra uma tela comum, que só carrega dado quando o usuário abre ou clica em algo, HTTP tradicional continua sendo mais simples de implementar, de escalar e de depurar. Não vale abrir uma conexão persistente pra cada usuário só porque parece mais moderno, isso tem custo real de servidor, já que cada conexão aberta consome memória e o servidor precisa segurar todas elas ativas ao mesmo tempo.

Socket.IO como alternativa

Em produção, é comum ver socket.io no lugar do ws puro. Ele usa WebSocket por baixo quando disponível, mas cai automaticamente pra outras estratégias (como polling) se a conexão WebSocket não for possível por algum motivo de rede ou proxy, além de já vir com reconexão automática e salas (grupos de clientes) prontas. Custa um pouco mais de peso na aplicação, mas resolve detalhe que, implementando ws puro, você acabaria tendo que resolver na mão de qualquer jeito.

Fechando

O ponto central é entender a diferença de modelo: HTTP é pergunta e resposta, WebSocket é uma conversa aberta dos dois lados. Não é sobre WebSocket ser "melhor", é sobre resolver um problema específico, que é o servidor precisar falar primeiro. Quando esse é o seu caso, ele economiza requisição desperdiçada e entrega uma experiência de verdade instantânea, em vez de uma tela que só parece atualizada.