Exercise 3: WebSockets in Go

Learn how to create a WebSocket server in Go for real-time bidirectional communication.

Why Use WebSockets?

WebSockets allow **real-time bidirectional communication** between a client and a server, unlike traditional HTTP requests.

Setting Up a WebSocket Server in Go

We use the `github.com/gorilla/websocket` package to manage WebSockets in Go.

package main

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

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

func handleConnection(w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        fmt.Println("WebSocket error:", err)
        return
    }
    defer conn.Close()
    
    for {
        _, msg, err := conn.ReadMessage()
        if err != nil {
            fmt.Println("Connection closed")
            break
        }
        fmt.Println("Message received:", string(msg))
        conn.WriteMessage(websocket.TextMessage, []byte("Message received successfully!"))
    }
}

func main() {
    http.HandleFunc("/ws", handleConnection)
    fmt.Println("WebSocket server running at ws://localhost:8080/ws")
    http.ListenAndServe(":8080", nil)
}

WebSocket Client in JavaScript

Use JavaScript to connect to the WebSocket server.

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

    socket.onopen = function() {
        console.log("Connection established");
        socket.send("Hello, server!");
    };

    socket.onmessage = function(event) {
        console.log("Message received:", event.data);
    };
</script>

Exercise Instructions

  • Create a file named websocket.go and implement the WebSocket server.
  • Add an HTML page with a WebSocket client in JavaScript.
  • Test the communication by sending and receiving messages.

Exercise Solution

Your WebSocket server should accept multiple connections and respond to client messages.

package main

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

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

func handleConnection(w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        fmt.Println("WebSocket error:", err)
        return
    }
    defer conn.Close()
    
    for {
        _, msg, err := conn.ReadMessage()
        if err != nil {
            fmt.Println("Connection closed")
            break
        }
        fmt.Println("Message received:", string(msg))
        conn.WriteMessage(websocket.TextMessage, []byte("Response: " + string(msg)))
    }
}

func main() {
    http.HandleFunc("/ws", handleConnection)
    fmt.Println("WebSocket server listening on ws://localhost:8080/ws")
    http.ListenAndServe(":8080", nil)
}

Best Practices & Common Errors

  • ✅ Always close connections properly (`defer conn.Close()`).
  • ✅ Handle read/write errors to prevent crashes.
  • ✅ Limit simultaneous connections to prevent server overload.
  • ⚠️ Always secure WebSocket connections with HTTPS in production.

📚 Learn more about WebSockets in Go:

Read the Official Documentation ← Previous Exercise Next Exercise →

🚀 Enjoying these exercises? If you find them useful and want to support my work, buying me a coffee would be greatly appreciated! ☕😊


☕ Buy me a coffee