View : 0

12/04/2026 18:17pm

EP.80 Building Connection Management for WebSocket Chat

EP.80 Building Connection Management for WebSocket Chat

#Go

#Golang

#WebSocket

#Connection Management

In a real-time WebSocket chat application with multiple concurrent users, Connection Management is one of the most critical components. Without proper connection handling, you could encounter serious issues such as:

  • Messages sent to the wrong user
  • Unreleased memory due to connection leaks
  • System crashes when handling too many users

 

🔸 Why Connection Management Matters

 

✅ Track connected users
Know who’s currently connected and possibly which device they're using.

✅ Deliver messages correctly
The system must know the exact WebSocket connection associated with each user to ensure correct message delivery.

✅ Detect disconnections
Handle timeouts, browser closures, or unstable internet connections.

✅ Improve system stability
Prevent memory leaks and ensure scalability for high user volumes.

 

🔸 A Good Connection Management Architecture Should Include:

 

  • Connection Hub / Pool:
    A centralized place to store all active connections.
  • User ↔ Connection Mapping:
    Mapping between userID and connection to allow targeted messaging.
  • Broadcast & Private Messaging Support:
    Send messages to all users or a specific user.

 

✅ Sample Golang Code: Simple Connection Management System

 

package main

import (
    "sync"
    "github.com/gorilla/websocket"
    "fmt"
)

// Represents each user's WebSocket connection
type Connection struct {
    ws   *websocket.Conn
    user string
}

// Hub keeps track of all connections
type Hub struct {
    connections map[string]*Connection // key: userID
    lock        sync.RWMutex
}

// Create a new Hub
func NewHub() *Hub {
    return &Hub{
        connections: make(map[string]*Connection),
    }
}

// ✅ Add a new connection
func (h *Hub) AddConnection(userID string, conn *websocket.Conn) {
    h.lock.Lock()
    defer h.lock.Unlock()

    h.connections[userID] = &Connection{
        ws:   conn,
        user: userID,
    }

    fmt.Printf("[+] %s connected\n", userID)
}

// ✅ Remove connection on disconnect
func (h *Hub) RemoveConnection(userID string) {
    h.lock.Lock()
    defer h.lock.Unlock()

    if conn, ok := h.connections[userID]; ok {
        conn.ws.Close()
        delete(h.connections, userID)
        fmt.Printf("[-] %s disconnected\n", userID)
    }
}

// ✅ Send private message to specific user
func (h *Hub) SendToUser(userID string, message string) {
    h.lock.RLock()
    defer h.lock.RUnlock()

    if conn, ok := h.connections[userID]; ok {
        err := conn.ws.WriteMessage(websocket.TextMessage, []byte(message))
        if err != nil {
            fmt.Println("[x] Send to", userID, "failed:", err)
        }
    }
}

// ✅ Broadcast message to all users
func (h *Hub) Broadcast(message string) {
    h.lock.RLock()
    defer h.lock.RUnlock()

    for userID, conn := range h.connections {
        err := conn.ws.WriteMessage(websocket.TextMessage, []byte(message))
        if err != nil {
            fmt.Println("[x] Broadcast to", userID, "failed:", err)
            conn.ws.Close()
            delete(h.connections, userID)
        }
    }
}

 

📝 Function Summary

FunctionPurpose
AddConnectionAdd a new WebSocket connection
RemoveConnectionRemove a disconnected WebSocket client
SendToUserSend a private message to one user
BroadcastSend a message to all connected users

 

✅ Full Code: main() and wsHandler()

 

package main

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

// Use previously defined Hub and Connection structs

var upgrader = websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool {
        return true // In production, restrict to trusted origins
    },
}

// WebSocket handler
func wsHandler(hub *Hub, w http.ResponseWriter, r *http.Request) {
    ws, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        fmt.Println("[x] Upgrade error:", err)
        return
    }

    userID := r.URL.Query().Get("user")
    if userID == "" {
        fmt.Println("[x] Missing user ID")
        ws.Close()
        return
    }

    hub.AddConnection(userID, ws)
    defer hub.RemoveConnection(userID)

    for {
        _, msg, err := ws.ReadMessage()
        if err != nil {
            fmt.Println("[x] Read error from", userID, ":", err)
            break
        }

        fmt.Printf("[>] Received from %s: %s\n", userID, string(msg))
        broadcastMsg := fmt.Sprintf("%s says: %s", userID, string(msg))
        hub.Broadcast(broadcastMsg)
    }
}

func main() {
    hub := NewHub()

    http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
        wsHandler(hub, w, r)
    })

    fmt.Println("🚀 WebSocket server started at :8080")
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        fmt.Println("[x] Server failed:", err)
    }
}

 

🔗 How the Connection Works

 

When a user connects via:

ws://localhost:8080/ws?user=alice

 

The system will:

  1. Parse userID = alice
  2. Store the WebSocket connection
  3. Accept messages from Alice
  4. Broadcast the message to all users
  5. Remove Alice’s connection if disconnected

 

💡 What This Code Can Do

 

✅ Track and manage each WebSocket connection
✅ Send private and broadcast messages
✅ Automatically remove disconnected users
✅ Support multiple users concurrently

 


 

🔧 Challenge: Add Connection Timeout

 

Try implementing timeout logic to remove idle users automatically:

time.AfterFunc(10*time.Minute, func() {
    hub.RemoveConnection(userID)
})

Or use ping/pong frames to detect connection liveness.

 

🔜 Coming Up Next…

 

EP.81 – Real-Time DB Integration with WebSocket
We’ll explore how to sync every message or user event to a database instantly via WebSocket!

 

Read more

🔵 Facebook: Superdev School  (Superdev)

📸 Instagram: superdevschool

🎬 TikTok: superdevschool

🌐 Website: www.superdev.school