WebSocket em JavaScript: aplicações real-time avançadas com Node.js

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Trabalho avançado com WebSocket em JavaScript: do protótipo à produção

\n

WebSocket é um protocolo que fornece comunicação full-duplex entre cliente e servidor através de uma única conexão TCP persistente. Em artigos anteriores, abordamos os fundamentos: estabelecimento de conexão, envio de mensagens e chats simples. No entanto, para criar aplicações real-time verdadeiramente robustas e escaláveis (jogos online, plataformas de negociação, sistemas de edição colaborativa), é necessário dominar técnicas avançadas. Neste material, exploraremos a arquitetura de um servidor WebSocket de nível de produção em Node.js, incluindo escalabilidade, gerenciamento de estado, autorização e tratamento de erros.

\n\n

1. Arquitetura avançada do servidor e gerenciamento de salas

\n

Um servidor WebSocket simples (baseado na biblioteca ws) gerencia todos os clientes em um único objeto global. Em projetos reais, é necessário isolamento lógico — salas (rooms) e canais.

\n

Vejamos um exemplo de arquitetura usando a classe RoomManager:

\n
const WebSocket = require('ws');\n\nclass RoomManager {\n    constructor() {\n        this.rooms = new Map(); // roomName -> Set<WebSocket>\n    }\n\n    join(ws, roomName) {\n        if (!this.rooms.has(roomName)) {\n            this.rooms.set(roomName, new Set());\n        }\n        this.rooms.get(roomName).add(ws);\n        ws.room = roomName; // Salva a sala no socket\n    }\n\n    leave(ws) {\n        if (ws.room && this.rooms.has(ws.room)) {\n            this.rooms.get(ws.room).delete(ws);\n            if (this.rooms.get(ws.room).size === 0) {\n                this.rooms.delete(ws.room);\n            }\n        }\n    }\n\n    broadcast(roomName, message, excludeWs = null) {\n        if (!this.rooms.has(roomName)) return;\n        this.rooms.get(roomName).forEach(client => {\n            if (client !== excludeWs && client.readyState === WebSocket.OPEN) {\n                client.send(JSON.stringify(message));\n            }\n        });\n    }\n}\n\n// Uso\nconst wss = new WebSocket.Server({ port: 8080 });\nconst roomManager = new RoomManager();\n\nwss.on('connection', (ws) => {\n    ws.on('message', (data) => {\n        const msg = JSON.parse(data);\n        switch (msg.type) {\n            case 'join':\n                roomManager.join(ws, msg.room);\n                break;\n            case 'message':\n                roomManager.broadcast(ws.room, { user: msg.user, text: msg.text }, ws);\n                break;\n        }\n    });\n\n    ws.on('close', () => roomManager.leave(ws));\n});
\n

Este código permite criar chats isolados ou sessões de jogo. Observe o tratamento do fechamento da conexão — isso é crítico para evitar vazamentos de memória.

\n\n

2. Escalabilidade: clusterização e Redis Pub/Sub

\n

Um único processo Node.js não pode utilizar eficientemente mais de um núcleo de CPU. Para escalar, usamos o módulo embutido cluster. No entanto, surge um problema: as conexões WebSocket estão vinculadas a um worker específico. Como enviar uma mensagem para um usuário conectado a outro worker?

\n

A solução é um broker de mensagens externo, por exemplo, Redis Pub/Sub.

\n
const cluster = require('cluster');\nconst http = require('http');\nconst { Server } = require('ws');\nconst redis = require('redis');\n\nconst REDIS_CHANNEL = 'ws:messages';\n\nif (cluster.isMaster) {\n    // Inicia workers de acordo com o número de núcleos\n    const numCPUs = require('os').cpus().length;\n    for (let i = 0; i < numCPUs; i++) {\n        cluster.fork();\n    }\n\n    cluster.on('exit', (worker) => {\n        console.log(`Worker ${worker.process.pid} morreu`);\n        cluster.fork(); // Reinicia\n    });\n} else {\n    // Worker\n    const server = http.createServer();\n    const wss = new Server({ server });\n\n    // Conecta ao Redis\n    const pub = redis.createClient();\n    const sub                

Blogs

Book Recommendations