Skip to main content
Brave Programmer Logo

BraveProgrammer

BraveProgrammer

HomeProjectsBlogsCoursesLessonsAbout

Site footer

BraveProgrammer

Free coding courses, practical tutorials, and real projects from BraveProgrammer. Learn web development with React, Next.js, and TypeScript.

Navigation

  • Home
  • Projects
  • Blogs
  • Courses

Resources

  • About
  • Lessons

© 2026 BraveProgrammer. All rights reserved.

  1. Courses
  2. /
  3. Go Programming Bootcamp

Lesson 51 of 60 · Go

Building a Simple Chat Server (WebSockets + Rooms)

Duration: 30 minutes

Chat Server Overview

This lesson explains the main concept clearly with beginner-friendly examples and background so you can learn why the code works.

We'll combine what we learned: WebSockets, goroutine pools, sync.Mutex, and JSON.

type client struct { conn *websocket.Conn; send chan []byte }

type hub struct {
    rooms map[string]map[*client]bool
    register   chan subscription
    unregister chan subscription
    broadcast  chan message
}

type subscription struct { room string; c *client }

type message struct { room string; data []byte }

Hub run loop

func (h *hub) run() {
    for {
        select {
        case sub := <-h.register:
            if h.rooms[sub.room] == nil { h.rooms[sub.room] = make(map[*client]bool) }
            h.rooms[sub.room][sub.c] = true
        case sub := <-h.unregister:
            if clients, ok := h.rooms[sub.room]; ok { delete(clients, sub.c) }
        case msg := <-h.broadcast:
            for c := range h.rooms[msg.room] { c.send <- msg.data }
        }
    }
}

Client read/write loops

func (c *client) readPump(h *hub, room string) {
    defer func() { h.unregister <- subscription{room, c}; c.conn.Close() }()
    for {
        _, data, err := c.conn.ReadMessage()
        if err != nil { break }
        h.broadcast <- message{room, data}
    }
}

func (c *client) writePump() {
    defer c.conn.Close()
    for msg := range c.send { c.conn.WriteMessage(websocket.TextMessage, msg) }
}

HTTP handler to upgrade

func serveWs(h *hub, w http.ResponseWriter, r *http.Request) {
    room := r.URL.Query().Get("room")
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil { return }
    client := &client{conn: conn, send: make(chan []byte, 256)}
    h.register <- subscription{room, client}
    go client.writePump()
    client.readPump(h, room)
}

Deploy with Docker (see lesson‑47) and test with a simple HTML page.

Info

This project demonstrates real‑world usage of channels, mutexes, and select.

Previous: Advanced Generics – Type Sets & ConstraintsNext: Building a Microservice with gRPC