Comunicação em Tempo Real

WebSockets

WebSockets mantêm uma conexão aberta em ambas as direções, permitindo que o servidor envie dados no momento em que eles mudam, em vez de esperar por uma solicitação.

intermediate14 min readUpdated 15 de set. de 2026
server.js
js
// server.js
import { WebSocketServer } from "ws";

const wss = new WebSocketServer({ port: 8080 });

wss.on("connection", (socket) => {
  socket.on("message", (data) => {
    for (const client of wss.clients) {
      if (client.readyState === client.OPEN) {
        client.send(data.toString());
      }
    }
  });
});
Iniciado por
Handshake de HTTP Upgrade
Transporte
Uma conexão TCP
Direção
Full duplex
Overhead
Muito baixo por mensagem
Seguro
wss:// via TLS
Alternativas
SSE, long polling

Por que importa

Por que WebSockets são importantes

O servidor pode fazer push

O servidor envia dados no instante em que acontecem, sem necessidade de requisição do cliente, o que é essencial para chats, presença e dados ao vivo.

Baixa latência e overhead

Após o handshake, as mensagens possuem um overhead de framing mínimo e não repetem cabeçalhos, ao contrário do polling.

Compatível com a plataforma web

A API do navegador é simples, roda nas mesmas portas que o HTTP e faz o upgrade para TLS com wss.

O panorama completo

As três partes de um WebSocket

Um upgrade HTTP, uma conexão full-duplex baseada em frames e a lógica de aplicação para salas, presença e reconexão.

O handshake

Upgrade

Uma requisição HTTP com um cabeçalho Upgrade se transforma em uma conexão WebSocket.

Frames

Troca

Pequenas mensagens estruturadas em frames viajam em ambas as direções através de uma única conexão.

O servidor

Gerenciar

Rastreia conexões, salas e presença, e escala utilizando pub/sub.

WebSockets em resumo

O núcleo dos WebSockets

Handshake de Upgrade

O cliente solicita o upgrade de uma requisição HTTP; o servidor responde com 101.

Frames

Mensagens de texto e binárias com um cabeçalho pequeno, além de frames de controle.

Full duplex

Ambos os lados podem enviar dados a qualquer momento pela mesma conexão.

Salas (Rooms)

Agrupam conexões para que as mensagens sejam enviadas ao subconjunto correto.

Heartbeats

Ping e pong detectam conexões mortas e evitam que proxies as encerrem.

Pub/sub

Transmissão entre instâncias de servidor através de Redis ou outro broker.

Uma breve historia

Do polling às conexões persistentes

  1. 2008

    Primeiros hacks

    Desenvolvedores simulam tempo real com long polling e técnicas de comet.

    08
  2. 2011

    WebSocket padronizado

    A RFC 6455 define o protocolo e os navegadores adicionam suporte.

    11
  3. 2012

    Socket.IO populariza

    Uma biblioteca com fallbacks e salas leva o tempo real para apps mainstream.

    12
  4. 2015

    Padrões de escalabilidade

    Redis pub/sub e sticky sessions tornam-se padrão para deploys de múltiplas instâncias.

    15
  5. Hoje

    Uma ferramenta entre várias

    WebSockets coexistem com Server-Sent Events, WebTransport e WebRTC.

    Hoje

O guia completo

WebSockets: Tudo que voce precisa saber

O que são WebSockets?

Um WebSocket é uma conexão persistente e full-duplex entre um cliente e um servidor. Após um handshake inicial via HTTP, ambos os lados podem enviar mensagens a qualquer momento através da mesma conexão TCP, com um overhead baixíssimo por mensagem. O servidor pode enviar dados no momento em que algo muda, em vez de esperar que o cliente faça a requisição.

Isso torna os WebSockets a ferramenta ideal para chats, indicadores de presença, dashboards em tempo real, edição colaborativa, jogos multiplayer e qualquer outra funcionalidade onde as atualizações devam chegar instantaneamente. Para atualizações simples de via única, Server-Sent Events costumam ser uma escolha mais simples.

O handshake de upgrade

Uma conexão WebSocket começa como uma requisição HTTP.

GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

Se o servidor aceitar, ele responde:

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

Após o 101 Switching Protocols, a conexão deixa de ser HTTP. Ela se torna um WebSocket, e os dados fluem em frames. Como começa via HTTP, ela funciona nas mesmas portas (80 e 443), passa pela maioria dos proxies e firewalls, e faz o upgrade para TLS com wss://.

Frames

As mensagens WebSocket são divididas em frames com um pequeno cabeçalho. Existem frames de texto, frames binários e frames de controle para ping, pong e close. O framing é minimalista, e é por isso que as mensagens WebSocket são muito mais leves do que requisições HTTP repetidas.

O protocolo também define códigos de fechamento (close codes), como 1000 para um fechamento normal e 1001 para “going away”, que ajudam ambos os lados a entender por que uma conexão foi encerrada.

A API do navegador

A API do cliente é pequena e orientada a eventos.

// client.js
const socket = new WebSocket("wss://api.example.com/chat");

socket.addEventListener("open", () => {
  socket.send(JSON.stringify({ type: "join", room: "general" }));
});

socket.addEventListener("message", (event) => {
  const message = JSON.parse(event.data);
  render(message);
});

socket.addEventListener("close", (event) => {
  console.log("closed", event.code, event.reason);
});

socket.addEventListener("error", () => {
  console.error("connection error");
});

Você envia com socket.send() e recebe eventos message. A propriedade readyState informa se o socket está conectando, aberto, fechando ou fechado.

Um servidor Node.js

A biblioteca ws é a maneira padrão de executar um servidor WebSocket no Node.

// server.js
import { WebSocketServer } from "ws";

const wss = new WebSocketServer({ port: 8080 });

wss.on("connection", (socket, request) => {
  socket.on("message", (data, isBinary) => {
    for (const client of wss.clients) {
      if (client !== socket && client.readyState === client.OPEN) {
        client.send(data, { binary: isBinary });
      }
    }
  });

  socket.on("close", () => console.log("client left"));
});

O servidor rastreia cada conexão e pode enviar mensagens para um único cliente, um subconjunto (uma room) ou para todos eles. O Socket.IO é uma alternativa de nível mais alto que adiciona rooms, acknowledgements, reconexão automática e fallbacks, ao custo de um protocolo e cliente customizados.

Salas e presença

Aplicações reais raramente transmitem mensagens para todos. Você rastreia qual conexão pertence a qual usuário ou sala.

// rooms.js
const rooms = new Map();

function join(socket, room) {
  if (!rooms.has(room)) rooms.set(room, new Set());
  rooms.get(room).add(socket);
}

function broadcast(room, payload) {
  for (const socket of rooms.get(room) ?? []) {
    if (socket.readyState === socket.OPEN) socket.send(payload);
  }
}

Salas, presença (quem está online) e indicadores de digitação são todos construídos a partir deste padrão, somados a heartbeats para detectar desconexões.

Heartbeats e reconexão

Uma conexão pode cair sem que nenhum dos lados perceba, especialmente em redes móveis ou atrás de proxies. Duas coisas a mantêm saudável:

  • Heartbeats. Envie um ping a cada 30 segundos e encerre a conexão se nenhum pong for recebido. Muitos proxies também fecham conexões inativas, portanto, o tráfego as mantém abertas.
  • Reconexão. O cliente deve tentar reconectar usando exponential backoff e restabelecer suas inscrições. É aqui que uma biblioteca como Socket.IO poupa esforço.
// heartbeat.js
const interval = setInterval(() => {
  for (const socket of wss.clients) {
    if (socket.isAlive === false) return socket.terminate();
    socket.isAlive = false;
    socket.ping();
  }
}, 30_000);

wss.on("close", () => clearInterval(interval));

Escalabilidade

Uma conexão WebSocket reside em exatamente uma instância de servidor, portanto, realizar broadcasts entre instâncias exige um canal compartilhado.

  • Pub/sub: publique mensagens no Redis, NATS ou outro broker, e faça com que cada instância as entregue aos seus clientes locais.
  • Sticky sessions: se a sua infraestrutura exigir, mantenha o cliente na mesma instância durante toda a vida útil da conexão.
  • Estado em um store compartilhado: mantenha a presença e a participação em salas no Redis para que qualquer instância possa responder.
  • Backpressure e limites: limite as conexões por instância e monitore a memória, pois cada conexão mantém um socket e algum estado.

Segurança

  • Sempre utilize wss:// em produção para que o tráfego seja criptografado.
  • Realize a autenticação durante o handshake e rejeite conexões não autorizadas.
  • Valide o header Origin para evitar o cross-site WebSocket hijacking.
  • Autorize cada mensagem; nunca presuma que um cliente conectado tem permissão para realizar determinada ação.
  • Limite o tamanho e a frequência das mensagens para evitar abusos.
  • Configure timeouts para que conexões abandonadas não causem vazamentos de memória (leaks).

Melhores práticas

  • Use WebSockets para atualizações bidirecionais de baixa latência e SSE para push unidirecional.
  • Implemente heartbeat e reconexão; nunca assuma que uma conexão está ativa.
  • Autentique durante o handshake e autorize cada mensagem.
  • Mantenha o estado por conexão reduzido e utilize rooms em um store compartilhado.
  • Use pub/sub para realizar broadcasts entre instâncias.
  • Defina limites de tamanho de mensagem e rate limits.
  • Encerre conexões inativas e monitore a contagem de conexões.

Erros comuns

  • Usar WebSockets para requisições e respostas simples onde o HTTP seria suficiente.
  • Esquecer os heartbeats e deixar conexões mortas abertas (leaking).
  • Fazer broadcast para todos os clientes quando apenas uma room deveria receber.
  • Armazenar o estado autoritativo apenas em memória e perdê-lo ao reiniciar.
  • Ignorar verificações de origin e a autorização de mensagens.
  • Assumir que o load balancer preservará a conexão sem a configuração adequada.

Próximos passos

WebSockets são a camada de conexão persistente sobre o TCP. Consolide seus conhecimentos com o guia de HTTP e TCP/IP & Sockets, execute-os no Node.js e compare o modelo de push com GraphQL subscriptions. Depois, construa uma pequena sala de chat com salas e heartbeats para ver esses padrões na prática.

Recebendo atualizações ao vivo

Um WebSocket envia mudanças assim que elas ocorrem. O polling repete requisições e desperdiça banda, especialmente quando nada muda.

Preferir
const socket = new WebSocket("wss://api.example.com/feed");

socket.addEventListener("message", (event) => {
  render(JSON.parse(event.data));
});
Evitar
setInterval(async () => {
  const res = await fetch("/api/feed");
  render(await res.json());
}, 1000);

Detectando conexões mortas

Uma conexão caída é frequentemente invisível para ambos os lados. Heartbeats a detectam e disparam a reconexão.

Preferir
const alive = setInterval(() => {
  if (socket.readyState !== socket.OPEN) return;
  socket.ping();
}, 30_000);
Evitar
// assume the connection is
// alive forever; dead peers
// leak resources silently

Perguntas frequentes

Perguntas frequentes

Keep learning

Related topics from the roadmap.

$ comecar a aprender

Pronto para aprender WebSockets?

Nosso tutorial interativo te guia por WebSockets passo a passo — com quizzes e codigo real que voce pode executar no navegador.