Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Sichere ProgrammierungI audited my own ML linter and had to withdraw its best evidence(21.09.2026 um 22:54 Uhr)
Sichere ProgrammierungQuantum Result Validation for Distributed Computing Systems(21.09.2026 um 22:54 Uhr)
Sichere ProgrammierungJWT Authentication and Role-Based Access Control in LocalHands(21.09.2026 um 22:56 Uhr)
Sichere ProgrammierungStochastic Parrot or Alien Mind?(21.09.2026 um 22:56 Uhr)
Sichere ProgrammierungBuilding AI for the Physical World Is a Different Engineering Problem(21.09.2026 um 22:58 Uhr)
Sichere ProgrammierungI audited my own ML linter and had to withdraw its best evidence(21.09.2026 um 22:54 Uhr)
Sichere ProgrammierungQuantum Result Validation for Distributed Computing Systems(21.09.2026 um 22:54 Uhr)
Sichere ProgrammierungJWT Authentication and Role-Based Access Control in LocalHands(21.09.2026 um 22:56 Uhr)
Sichere ProgrammierungStochastic Parrot or Alien Mind?(21.09.2026 um 22:56 Uhr)
Sichere ProgrammierungBuilding AI for the Physical World Is a Different Engineering Problem(21.09.2026 um 22:58 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Building A Real-Time Communication System Using Go and WebSocket

Real-time applications like chat systems, dashboards, or multiplayer games rely on persistent, low-latency communication between client and server. Traditional HTTP is request-response only, but it can’t push data to the client unless the c…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

Real-time applications like chat systems, dashboards, or multiplayer games rely on persistent, low-latency communication between client and server. Traditional HTTP is request-response only, but it can’t push data to the client unless the client keeps polling. That’s where WebSockets come in.



In this article, we’ll explore how WebSockets work, how connections are established and managed in Go using the Gorilla WebSocket library, and how to safely handle multiple concurrent clients with Go’s concurrency primitives.



We’ll build on a simple Go project using only the standard net/http router and Gorilla WebSocket.






What is a WebSocket?



A WebSocket is a full-duplex communication channel over a single TCP connection. Once established, both client and server can send messages to each other anytime without re-establishing the connection.



Unlike HTTP:




  • WebSockets stay open until one side closes it.

  • Communication happens through lightweight frames, not HTTP requests.

  • Data can flow in both directions independently.






How a WebSocket Connection is Formed



The WebSocket handshake starts as a standard HTTP GET request with an Upgrade header:




GET /ws HTTP/1.1
Host: localhost:8080
Upgrade: websocket
Connection: Upgrade






If the server accepts it, it responds with a 101 Switching Protocols status, upgrading the connection to WebSocket. From that point, the connection is no longer HTTP, it’s a persistent socket.



In Go, this upgrade is handled by Gorilla’s Upgrader:




var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool { return true },
}






The CheckOrigin function lets us control which clients can connect. Setting it to always return true allows all origins, good for development, not for production.






Connection Establishment and Storage



When a client connects to /ws, the handler upgrades the request:




conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("Upgrade error:", err)
return
}






Once upgraded, conn is a *websocket.Conn, which represents an open connection to a client.

We store each connection in memory along with the client’s username (sent in the request header):




mu.Lock()
Connections = append(Connections, map[string]*websocket.Conn{username: conn})
mu.Unlock()






We use a global slice of maps to keep track of all connected users.

A sync.Mutex ensures that concurrent reads and writes to the Connections slice are thread-safe, since multiple clients can connect or disconnect at the same time.





Reading and Writing Messages



After establishing the connection, the server starts listening for messages:




for {
messageType, msg, err := conn.ReadMessage()
if err != nil {
log.Printf("[%s] read error: %v", username, err)
break
}

log.Printf("[%s] says: %s", username, msg)

resp := fmt.Sprintf("Response to %s: %s", username, msg)
conn.WriteMessage(messageType, []byte(resp))
}






ReadMessage() blocks until a new message arrives. When it does, it returns the message type, the payload, and any error.



The messageType is important because WebSockets can carry different kinds of messages.






WebSocket Message Types





  1. TextMessage (1): UTF-8 encoded text.


  2. BinaryMessage (2): Arbitrary binary data.


  3. PingMessage (9): Sent by one peer to check if the connection is alive.


  4. PongMessage (10): Sent automatically in response to a ping.


  5. CloseMessage (8): Sent when either side wants to terminate the connection.



Most applications only use text and binary frames, but ping/pong frames are crucial for keeping the connection healthy.






Detecting and Closing Idle Connections



In a real-world system, we don’t want idle connections hanging around forever.

We can use SetReadDeadline() to close connections that haven’t received messages for a specific time:




const idleTimeout = 60 * time.Second
conn.SetReadDeadline(time.Now().Add(idleTimeout))
conn.SetPongHandler(func(string) error {
conn.SetReadDeadline(time.Now().Add(idleTimeout))
return nil
})






This means:




  • The server expects a message or pong frame every 60 seconds.

  • Each time one arrives, the deadline resets.

  • If the timer expires without activity, ReadMessage() returns a timeout error, and we close the connection.



This is how we automatically disconnect idle clients while keeping active ones alive.






Cleaning Up Disconnected Clients



When a connection closes, we must remove it from our global store to prevent memory leaks:




func removeConnection(username string) {
mu.Lock()
defer mu.Unlock()

var updated []map[string]*websocket.Conn
for _, m := range Connections {
if _, ok := m[username]; !ok {
updated = append(updated, m)
}
}
Connections = updated
}






This ensures that only active connections remain in memory.






Sending Messages to Specific Clients



Sometimes, you need to send data to a particular user. We can look up the connection by username and send directly:




func SendMessageToSpecificUser(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
targetUser := string(body)

mu.Lock()
defer mu.Unlock()

for _, item := range Connections {
for username, conn := range item {
if username == targetUser {
conn.WriteMessage(websocket.TextMessage, []byte("hi "+username))
log.Printf("Sent message to %s", username)
w.Write([]byte("sent"))
return
}
}
}
w.Write([]byte("user not found"))
}






This can easily be extended to support broadcasting messages to all clients or to a subset (like chat rooms).






Concurrency and Multithreading in WebSocket Handling



Each HTTP request in Go runs in its own goroutine.

That means every WebSocket connection gets a dedicated goroutine when the handler runs:




mux.HandleFunc("/ws", handlers.WebsocketHandler)






Inside that goroutine:




  • The for loop reading messages is blocking, but isolated to that connection.


  • sync.Mutex ensures shared data structures (like Connections) remain safe when multiple goroutines modify them simultaneously.

  • The Go scheduler handles concurrency efficiently, thousands of WebSocket connections can run in parallel on a single server.



This concurrency model is what makes Go such a great fit for real-time applications.






Putting It All Together



Let’s walk through building and testing the complete WebSocket setup from scratch.






Project Setup



Create your project:




mkdir websocket-chat-appp
cd websocket-chat-appp
go mod init websocket-chat-appp






Install Gorilla WebSocket:




go get github.com/gorilla/websocket






Project structure:




websocket-chat-app/
│── go.mod
├── main.go
└── handlers/
└── websocket_handlers.go









main.go






package main

import (
"log"
"net/http"
"websocket-chat-app/handlers"
)

func main() {
mux := http.NewServeMux()
mux.HandleFunc("/ws", handlers.WebsocketHandler)
mux.HandleFunc("/show", handlers.PrintConnections)
mux.HandleFunc("POST /send", handlers.SendMessageToSpecificUser)

log.Printf("Server started on :8080")
http.ListenAndServe(":8080", mux)
}









handlers/websocket_handlers.go






package handlers

import (
"fmt"
"io"
"log"
"net/http"
"sync"
"time"

"github.com/gorilla/websocket"
)

// Global variables to store all active connections
var (
Connections []map[string]*websocket.Conn
mu sync.Mutex
)

var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool { return true },
}

// WebsocketHandler handles new WebSocket connections
func WebsocketHandler(w http.ResponseWriter, r *http.Request) {
username := r.URL.Query().Get("username")
if username == "" {
http.Error(w, "username query param required", http.StatusBadRequest)
return
}

conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("Upgrade error:", err)
return
}

mu.Lock()
Connections = append(Connections, map[string]*websocket.Conn{username: conn})
mu.Unlock()

log.Printf("[%s] connected", username)

go handleConnection(username, conn)
}

// handleConnection reads messages and handles connection lifecycle
func handleConnection(username string, conn *websocket.Conn) {
defer func() {
removeConnection(username)
conn.Close()
log.Printf("[%s] disconnected", username)
}()

const idleTimeout = 60 * time.Second
conn.SetReadDeadline(time.Now().Add(idleTimeout))
conn.SetPongHandler(func(string) error {
conn.SetReadDeadline(time.Now().Add(idleTimeout))
return nil
})

for {
msgType, msg, err := conn.ReadMessage()
if err != nil {
log.Printf("[%s] read error: %v", username, err)
break
}

log.Printf("[%s] says: %s", username, msg)
resp := fmt.Sprintf("Response to %s: %s", username, msg)
conn.WriteMessage(msgType, []byte(resp))
}
}

// removeConnection cleans up disconnected clients
func removeConnection(username string) {
mu.Lock()
defer mu.Unlock()

var updated []map[string]*websocket.Conn
for _, m := range Connections {
if _, ok := m[username]; !ok {
updated = append(updated, m)
}
}
Connections = updated
}

// PrintConnections displays all connected usernames
func PrintConnections(w http.ResponseWriter, _ *http.Request) {
mu.Lock()
defer mu.Unlock()

fmt.Fprintln(w, "Connected users:")
for _, conn := range Connections {
for username := range conn {
fmt.Fprintln(w, "-", username)
}
}
}

// SendMessageToSpecificUser sends a message to a specific user
func SendMessageToSpecificUser(w http.ResponseWriter, r *http.Request) {
body, _ := io.ReadAll(r.Body)
targetUser := string(body)

mu.Lock()
defer mu.Unlock()

for _, item := range Connections {
for username, conn := range item {
if username == targetUser {
conn.WriteMessage(websocket.TextMessage, []byte("hi "+username))
log.Printf("Sent message to %s", username)
w.Write([]byte("sent"))
return
}
}
}
w.Write([]byte("user not found"))
}









Running the Server



Start the Go server:




go run main.go






Output:




2025/10/09 22:10:41 Server started on:8080









Testing with Postman



Now, let's see how our app works.

Open Postman, then make a WebSocket connection to localhost:8080/ws. Here I am using passing mugdho as the username, in the header.



WebSocket Request - Mugdho



Let's make another WebSocket request. Here I am using "mila" as the username in the header.



WebSocket Connection - Mila



Let's see the connected users using HTTP REST API.



Show All Connected Users - 2 users



Now I am sending messages from the connection "Mugdho"





But I'm not sending any messages from "Mila". So the connection is closed.





Now, establish both connections again and send a message to a specific user. I am sending a message to "Mila".





Let's see if Mila received the message or not.





As you can see, Mila received the message successfully.






Summary



Here’s what we covered:





  • How WebSockets work and how they differ from HTTP


  • How to establish and upgrade a connection using Gorilla WebSocket


  • Message types and how to read/write frames


  • How to detect idle clients using SetReadDeadline and close them cleanly


  • Storing and managing connections safely with sync.Mutex


  • Concurrency in Go each WebSocket runs in its own goroutine

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Building A Real-Time Communication System Using Go and WebSocket

Thematisch verwandte Begriffe: Building, RealTime, Communication, System · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-79918 | MaxKB is an open-source AI assistant for enterprise. Prior to version 2.…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick