DEV Community

Cover image for What Is Websocket ?
Mohamed Elmorsy
Mohamed Elmorsy

Posted on

What Is Websocket ?

What Is WebSocket?

You open a live football score page. The score updates every few seconds — but you never clicked refresh. You open a chat app and your friend's message appears instantly. You watch a real-time stock dashboard and the numbers change as trades happen.

None of this is possible with plain HTTP. Every one of those features runs on WebSocket.


The Problem HTTP Can't Solve

HTTP follows a strict rule: the client asks, the server answers, the connection closes. This works perfectly for loading pages and fetching data. But it falls apart for anything real-time.

Before WebSocket, developers hacked around this with two approaches:

Polling

The client asks the server "any updates?" every few seconds — whether there are updates or not.

Client → "Any new messages?"  Server → "No."
Client → "Any new messages?"  Server → "No."
Client → "Any new messages?"  Server → "Yes! Here's one."
Enter fullscreen mode Exit fullscreen mode

Wasteful. Most requests are empty. Latency depends on the poll interval.

Long Polling

The client sends a request and the server holds it open until it has data to send, then responds and the cycle repeats.

Client → "Any updates?"
Server → [holds the connection...]
Server → [holds the connection...]
Server → "Here's data!"  → connection closes
Client → "Any updates?"  → starts again
Enter fullscreen mode Exit fullscreen mode

Better, but still fundamentally request/response. Every delivery requires reconnecting.

WebSocket's answer: Open one persistent connection. Both sides can send data at any time, in any direction, without asking permission first.


What Is WebSocket?

WebSocket is a communication protocol that provides a persistent, full-duplex channel over a single TCP connection. It was standardized in 2011 as RFC 6455.

Full-duplex means both the client and server can send messages simultaneously and independently — like a phone call, not a walkie-talkie.

Key characteristics:

  • Persistent connection — stays open until explicitly closed
  • Full-duplex — server and client both push freely, no turn-taking
  • Low overhead — no HTTP headers on every message, just a small frame
  • Real-time — sub-millisecond latency for live data
  • Built on HTTP — starts as an HTTP request, then upgrades

WebSocket full-duplex connection diagram


How WebSocket Works: The Upgrade Handshake

WebSocket does not replace HTTP — it starts with HTTP, then upgrades the connection.

Step 1 — The Client Sends an Upgrade Request

GET /chat HTTP/1.1
Host: api.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Enter fullscreen mode Exit fullscreen mode

The key headers are Upgrade: websocket and Connection: Upgrade. They tell the server: "I want to switch protocols."

Step 2 — The Server Accepts

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Enter fullscreen mode Exit fullscreen mode

Status code 101 Switching Protocols — the only time you'll see that number. From this point on, the HTTP handshake is over. The TCP connection stays open and is now a WebSocket channel.

Step 3 — Full-Duplex Communication

Client → "Hello!"
Server → "Hi! 3 users online."
Server → "New message from Bob: 'Hey everyone'"   ← server pushes without being asked
Client → "Got it, thanks."
Server → "Bob has left the chat."                 ← server pushes again
Enter fullscreen mode Exit fullscreen mode

WebSocket upgrade handshake


When to Use WebSocket

WebSocket is not a replacement for HTTP. Use the right tool for the right job:

Use Case Use HTTP Use WebSocket
Fetching user profile
Submitting a form
Live chat
Real-time notifications
Live sports scores
Stock price dashboards
Multiplayer game state
Collaborative editing
File upload
Fetching an API resource

Rule of thumb: If the server needs to push data to the client without the client asking first — use WebSocket. Everything else — use HTTP.


WebSocket in Go

The standard library does not include a WebSocket implementation. The most widely used package is gorilla/websocket.

go get github.com/gorilla/websocket
Enter fullscreen mode Exit fullscreen mode

Building a WebSocket Server

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/gorilla/websocket"
)

// upgrader converts an HTTP connection into a WebSocket connection
var upgrader = websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool {
        return true // allow all origins in development
    },
}

func handleWS(w http.ResponseWriter, r *http.Request) {
    // 1. Upgrade the HTTP connection to WebSocket
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Println("Upgrade error:", err)
        return
    }
    defer conn.Close()

    fmt.Println("Client connected:", conn.RemoteAddr())

    // 2. Read and echo messages in a loop
    for {
        messageType, msg, err := conn.ReadMessage()
        if err != nil {
            log.Println("Client disconnected:", err)
            break
        }

        fmt.Printf("Received: %s\n", msg)

        // 3. Send a response back to the same client
        if err := conn.WriteMessage(messageType, msg); err != nil {
            log.Println("Write error:", err)
            break
        }
    }
}

func main() {
    http.HandleFunc("/ws", handleWS)
    log.Println("WebSocket server running on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}
Enter fullscreen mode Exit fullscreen mode

Building a WebSocket Client

package main

import (
    "fmt"
    "log"

    "github.com/gorilla/websocket"
)

func main() {
    // 1. Dial the WebSocket server (handles the upgrade handshake automatically)
    conn, _, err := websocket.DefaultDialer.Dial("ws://localhost:8080/ws", nil)
    if err != nil {
        log.Fatal("Connection error:", err)
    }
    defer conn.Close()

    // 2. Send a message to the server
    if err := conn.WriteMessage(websocket.TextMessage, []byte("Hello from client!")); err != nil {
        log.Fatal("Write error:", err)
    }

    // 3. Read the server's response
    _, msg, err := conn.ReadMessage()
    if err != nil {
        log.Fatal("Read error:", err)
    }

    fmt.Printf("Server replied: %s\n", msg)
}
Enter fullscreen mode Exit fullscreen mode

Broadcasting to All Connected Clients (Hub Pattern)

Real-world apps need to send messages to all connected clients — not just echo back to one. The standard pattern in Go is a Hub:

package main

import (
    "log"
    "net/http"

    "github.com/gorilla/websocket"
)

// Hub manages all active WebSocket connections
type Hub struct {
    clients    map[*websocket.Conn]bool
    broadcast  chan []byte
    register   chan *websocket.Conn
    unregister chan *websocket.Conn
}

func newHub() *Hub {
    return &Hub{
        clients:    make(map[*websocket.Conn]bool),
        broadcast:  make(chan []byte),
        register:   make(chan *websocket.Conn),
        unregister: make(chan *websocket.Conn),
    }
}

// Run listens for events and manages the client list
func (h *Hub) Run() {
    for {
        select {
        case conn := <-h.register:
            h.clients[conn] = true
            log.Println("Client registered:", conn.RemoteAddr())

        case conn := <-h.unregister:
            if _, ok := h.clients[conn]; ok {
                delete(h.clients, conn)
                conn.Close()
                log.Println("Client unregistered:", conn.RemoteAddr())
            }

        case msg := <-h.broadcast:
            // Send the message to every connected client
            for conn := range h.clients {
                if err := conn.WriteMessage(websocket.TextMessage, msg); err != nil {
                    h.unregister <- conn
                }
            }
        }
    }
}

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

func handleWS(hub *Hub, w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Println("Upgrade error:", err)
        return
    }

    hub.register <- conn

    defer func() {
        hub.unregister <- conn
    }()

    for {
        _, msg, err := conn.ReadMessage()
        if err != nil {
            break
        }
        hub.broadcast <- msg
    }
}

func main() {
    hub := newHub()
    go hub.Run()

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

    log.Println("Chat server running on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}
Enter fullscreen mode Exit fullscreen mode

HTTP vs WebSocket

Feature HTTP WebSocket
Connection Opens and closes per request Stays open persistently
Direction Client → Server only Both directions simultaneously
Latency Per-request overhead Near zero after handshake
Overhead Full headers on every message Small frame header (~2–10 bytes)
Use case Data fetching, CRUD Real-time, push, streaming
Protocol upgrade Starts as HTTP, upgrades via 101
State Stateless Stateful

Summary

Concept What It Is
WebSocket A protocol for persistent, full-duplex TCP communication
Full-duplex Both sides can send messages simultaneously
Upgrade handshake An HTTP 101 exchange that converts the connection
Hub pattern A Go struct that manages all connections and broadcasts
gorilla/websocket The standard Go library for WebSocket servers and clients

Further Reading & Watch


You now understand the full communication toolkit of the modern web: HTTP for requests, HTTPS for security, REST and GraphQL for structured APIs, and WebSockets for real-time streams. Every chat app, live dashboard, and multiplayer game you've ever used speaks this language.

The next step? Build something with all of it.

Top comments (0)