WebSocket em Go: criação de aplicações real-time de nível avançado

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
```html

Introdução: além do WebSocket simples em Go



Exemplos básicos de WebSocket em Go geralmente mostram uma simples conexão de eco. Em projetos reais de produção — desde terminais de bolsa de valores até jogos multiplayer e sistemas de alerta — é necessário muito mais: gerenciamento de salas, Graceful Shutdown, escalabilidade e tratamento correto de erros. Neste artigo, vamos analisar um padrão avançado para construir aplicações em tempo real em Go usando a biblioteca gorilla/websocket.



Vamos criar uma arquitetura baseada em Hub (central dispatcher) e Client (conexão individual), adicionar suporte a salas, um mecanismo de tolerância a falhas e mostrar como finalizar corretamente a execução do servidor.



Arquitetura Hub e Client: a base do servidor em tempo real



Por que Hub?

Cada cliente WebSocket é uma goroutine separada. Gerenciá-los diretamente a partir de um handler HTTP é perigoso: isso leva a condições de corrida e vazamentos de memória. O padrão Hub resolve o problema atuando como um canal único para registro, remoção e distribuição de mensagens.



Implementação do Hub

package main

import ( "log" "sync")

type Client struct { hub *Hub send chan []byte room string}

type Hub struct { clients map[*Client]bool broadcast chan Message register chan *Client unregister chan *Client mu sync.RWMutex}

type Message struct { Room string Data []byte Sender *Client}

func NewHub() *Hub { return &Hub{ clients: make(map[*Client]bool), broadcast: make(chan Message, 256), register: make(chan *Client), unregister: make(chan *Client), }}

func (h *Hub) Run() { for { select { case client := <-h.register: h.mu.Lock() h.clients[client] = true h.mu.Unlock() log.Printf("Cliente conectado. Total: %d", len(h.clients))

case client := <-h.unregister: h.mu.Lock() if _, ok := h.clients[client]; ok { delete(h.clients, client) close(client.send) } h.mu.Unlock()

case message := <-h.broadcast: h.mu.RLock() for client := range h.clients { // Envia apenas para a sala correta if client.room == message.Room || message.Room == "" { select { case client.send <- message.Data: default: // Se o canal estiver cheio — desconecta o cliente h.mu.RUnlock() h.unregister <- client h.mu.RLock() } } } h.mu.RUnlock() } }}


Pontos-chave:

  • Canais — register, unregister, broadcast — sincronizam as goroutines com segurança.
  • RWMutex — permite ler a lista de clientes simultaneamente, mas bloqueia a escrita.
  • Roteamento baseado em sala — a mensagem é enviada apenas para clientes na mesma sala.


Gerenciamento de salas e inscrições



Salas (Rooms) são grupos lógicos de clientes. Por exemplo, em um chat, cada conversa tem sua própria sala. Em nosso Hub, a sala é definida pelo campo room do Client. Vamos ver como um cliente se inscreve em uma sala.



Handler HTTP com WebSocket Upgrade

import (    "net/http"    "github.com/gorilla/websocket")

var upgrader = websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, CheckOrigin: func(r *http.Request) bool { return true // Para produção, substituir pela verificação de origin },}

func serveWs(hub *Hub, w http.ResponseWriter, r *http.Request) { conn, err := upgrader.Upgrade(w, r, nil) if err != ```

Blogs

Book Recommendations