Sling Academy
Home/Golang/Broadcasting Messages to Multiple Clients with WebSockets in Go

Broadcasting Messages to Multiple Clients with WebSockets in Go

Last updated: November 26, 2024

WebSockets provide full-duplex communication channels over a single TCP connection. This is especially beneficial for real-time web applications, allowing efficient interaction between clients and servers. In this tutorial, we will focus on building a WebSocket server in Go that can broadcast messages to multiple connected clients.

Setting Up a WebSocket Server

First, we need to install the Gorilla WebSocket package, which is a well-maintained library in the Go ecosystem for handling WebSockets. Run the following command to install it:

go get -u github.com/gorilla/websocket

Creating a Basic WebSocket Server

Let’s start by creating a main.go file, where we'll define a simple HTTP server and handle WebSocket upgrades:


package main

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

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

func handleConnections(w http.ResponseWriter, r *http.Request) {
    ws, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer ws.Close()

    for {
        _, message, err := ws.ReadMessage()
        if err != nil {
            fmt.Println(err)
            break
        }
        fmt.Printf("Received: %s\n", message)
    }
}

func main() {
    http.HandleFunc("/ws", handleConnections)
    fmt.Println("HTTP server started on :8080")
    http.ListenAndServe(":8080", nil)
}

Broadcasting Messages

Now that we have a basic WebSocket server set up, let’s extend it to handle broadcasting messages to all connected clients. We will maintain a list of all connected clients and loop through these to broadcast messages.

Maintaining Client Connections

We can use a map to keep track of connected clients. We update our server code as follows:


var clients = make(map[*websocket.Conn]bool)
var broadcast = make(chan []byte)

func handleConnections(w http.ResponseWriter, r *http.Request) {
    ws, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer ws.Close()

    clients[ws] = true

    for {
        _, message, err := ws.ReadMessage()
        if err != nil {
            delete(clients, ws)
            fmt.Println(err)
            break
        }
        broadcast <- message
    }
}

func handleMessages() {
    for {
        message := <-broadcast
        for client := range clients {
            err := client.WriteMessage(websocket.TextMessage, message)
            if err != nil {
                fmt.Println(err)
                client.Close()
                delete(clients, client)
            }
        }
    }
}

func main() {
    http.HandleFunc("/ws", handleConnections)
    go handleMessages()
    fmt.Println("HTTP server started on :8080")
    http.ListenAndServe(":8080", nil)
}

With this setup, any message received from a client will be broadcast to all other connected clients. This simple server can now be scaled to support many clients simultaneously.

Testing the WebSocket Server

You can use tools like WebSocket.org Echo Test or create simple HTML with JavaScript to test your server. Here is a simple HTML file that connects to your server:





    WebSocket Client


    
        let socket = new WebSocket("ws://localhost:8080/ws");

        socket.onopen = function(e) {
            alert("Connection established");
            socket.send("Hello Server!");
        };

        socket.onmessage = function(event) {
            alert(`Data received from server: ${event.data}`);
        };

        socket.onclose = function(event) {
            if (event.wasClean) {
                alert(`Connection closed cleanly, code=${event.code} reason=${event.reason}`);
            } else {
                alert('Connection died');
            }
        };

        socket.onerror = function(error) {
            alert(`Error: ${error.message}`);
        };
    


Conclusion

In this article, we learned how to implement WebSocket communication in Go, with a focus on broadcast messaging to multiple connected clients. By enhancing the server capabilities, you can develop a robust real-time web application capable of serving a myriad of use cases such as real-time chat applications, live collaboration tools, gaming, and more.

Next Article: Using Gorilla WebSocket Package for Robust WebSocket Applications in Go

Previous Article: Implementing a Real-Time Chat Application Using WebSockets in Go

Series: Websocket & Chat Programs in Go

Golang

Related Articles

You May Also Like

  • How to remove HTML tags in a string in Go
  • How to remove special characters in a string in Go
  • How to remove consecutive whitespace in a string in Go
  • How to count words and characters in a string in Go
  • Relative imports in Go: Tutorial & Examples
  • How to run Python code with Go
  • How to generate slug from title in Go
  • How to create an XML sitemap in Go
  • How to redirect in Go (301, 302, etc)
  • Using Go with MongoDB: CRUD example
  • Auto deploy Go apps with CI/ CD and GitHub Actions
  • Fixing Go error: method redeclared with different receiver type
  • Fixing Go error: copy argument must have slice type
  • Fixing Go error: attempted to use nil slice
  • Fixing Go error: assignment to constant variable
  • Fixing Go error: cannot compare X (type Y) with Z (type W)
  • Fixing Go error: method has pointer receiver, not called with pointer
  • Fixing Go error: assignment mismatch: X variables but Y values
  • Fixing Go error: array index must be non-negative integer constant