12/04/2026 18:17pm

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 betweenuserIDand 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
| Function | Purpose |
|---|---|
| AddConnection | Add a new WebSocket connection |
| RemoveConnection | Remove a disconnected WebSocket client |
| SendToUser | Send a private message to one user |
| Broadcast | Send 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:
- Parse
userID = alice - Store the WebSocket connection
- Accept messages from Alice
- Broadcast the message to all users
- 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