Building a Lightweight WebSocket Server in Go

Table of Contents

  1. Introduction
  2. Prerequisites
  3. Setting up Environment
  4. Creating a WebSocket Server
  5. Handling WebSocket Connections
  6. Broadcasting Messages
  7. Conclusion

Introduction

In this tutorial, we will learn how to build a lightweight WebSocket server using Go programming language. By the end of this tutorial, you will have a working WebSocket server that can handle multiple client connections and broadcast messages to all connected clients.

WebSocket is a communication protocol that provides full-duplex communication over a single, long-lived, connection. This makes it suitable for applications that require real-time updates, such as chat applications, gaming, and collaborative editing tools.

Prerequisites

To follow along with this tutorial, you should have a basic understanding of Go programming language and familiarity with concepts such as functions, variables, and structs. You will also need to have Go installed on your system. If you haven’t done so, head over to the official Go website and follow the installation instructions for your operating system.

Setting up Environment

Before we dive into building our WebSocket server, let’s create a new Go module and set up the necessary packages and dependencies.

  1. Create a new directory for your project:

    ```shell
    mkdir websocket-server
    cd websocket-server
    ```
    
  2. Initialize a new Go module:

    ```shell
    go mod init github.com/your-username/websocket-server
    ```
    
  3. Install the Gorilla WebSocket library, which provides a WebSocket implementation for Go:

    ```shell
    go get github.com/gorilla/websocket
    ```
    

    With our environment set up, we can now proceed to create our WebSocket server.

Creating a WebSocket Server

  1. Create a new file called main.go and open it in a text editor.

  2. Import the required packages:

    ```go
    package main
    
    import (
        "fmt"
        "log"
        "net/http"
        "github.com/gorilla/websocket"
    )
    ```
    
  3. Define a struct to represent our WebSocket server:

    ```go
    type Server struct {
        clients   map[*websocket.Conn]bool
        broadcast chan []byte
    }
    ```
    
  4. Define a method to handle incoming WebSocket connections:

    ```go
    func (s *Server) handleConnections(w http.ResponseWriter, r *http.Request) {
        upgrader := websocket.Upgrader{
            CheckOrigin: func(r *http.Request) bool {
                return true
            },
        }
    
        conn, err := upgrader.Upgrade(w, r, nil)
        if err != nil {
            log.Fatal(err)
        }
    
        s.clients[conn] = true
    
        for {
            var msg []byte
            err := conn.ReadMessage(&msg)
            if err != nil {
                log.Printf("Error: %v", err)
                delete(s.clients, conn)
                break
            }
            s.broadcast <- msg
        }
    }
    ```
    
  5. Define a method to handle broadcasting messages to all connected clients:

    ```go
    func (s *Server) handleMessages() {
        for {
            msg := <-s.broadcast
            for client := range s.clients {
                err := client.WriteMessage(websocket.TextMessage, msg)
                if err != nil {
                    log.Printf("Error: %v", err)
                    client.Close()
                    delete(s.clients, client)
                }
            }
        }
    }
    ```
    
  6. Modify the main function to initialize the WebSocket server:

    ```go
    func main() {
        server := Server{
            clients:   make(map[*websocket.Conn]bool),
            broadcast: make(chan []byte),
        }
    
        http.HandleFunc("/ws", server.handleConnections)
    
        go server.handleMessages()
    
        log.Println("WebSocket server started on localhost:8000")
        err := http.ListenAndServe(":8000", nil)
        if err != nil {
            log.Fatal(err)
        }
    }
    ```
    
  7. Save the file and build the project:

    ```shell
    go build
    ```
    

    Congratulations! You have just created a basic WebSocket server in Go. Let’s now move on to handling WebSocket connections.

Handling WebSocket Connections

Our WebSocket server is currently set up to handle incoming connections and broadcast messages to all connected clients. However, we don’t have any web page to test our server yet. We’ll create a simple HTML file that connects to the WebSocket server and sends/receives messages.

  1. Create a new directory called static in the root of your project.

  2. Inside the static directory, create a new file called index.html and open it in a text editor.

  3. Add the following HTML code to the index.html file:

    ```html
    <!DOCTYPE html>
    <html>
    <head>
        <title>WebSocket Example</title>
    </head>
    <body>
        <input type="text" id="message">
        <button onclick="sendMessage()">Send</button>
    
        <ul id="messages"></ul>
    
        <script>
            var socket = new WebSocket("ws://localhost:8000/ws");
    
            socket.onmessage = function(event) {
                var messageList = document.getElementById("messages");
                var li = document.createElement("li");
                li.appendChild(document.createTextNode(event.data));
                messageList.appendChild(li);
            };
    
            function sendMessage() {
                var messageInput = document.getElementById("message");
                var message = messageInput.value;
    
                socket.send(message);
    
                messageInput.value = "";
            }
        </script>
    </body>
    </html>
    ```
    
  4. Save the file.

Broadcasting Messages

With our WebSocket server and web page set up, let’s test our application by broadcasting messages to all connected clients.

  1. Start the WebSocket server by running the compiled executable:

    ```shell
    ./websocket-server
    ```
    
  2. Open a web browser and navigate to http://localhost:8000/static/index.html.

  3. Open multiple browser tabs or windows and connect all of them to the WebSocket server.

  4. Enter a message in any of the browser tabs/windows and click the “Send” button.

    You should see the message appear on all connected clients' screens.
    

    Congratulations! You have successfully built a lightweight WebSocket server in Go. You can now extend the functionality of the server by implementing additional features such as user authentication, chat rooms, and message persistence.

Conclusion

In this tutorial, we have learned how to build a lightweight WebSocket server using Go programming language. We started by setting up the environment and installing the necessary packages. Then, we created a struct to represent our WebSocket server and defined methods to handle incoming connections and broadcast messages. Finally, we tested our server by creating a simple HTML file that connects to the server and sends/receives messages.

WebSockets provide a powerful mechanism for building real-time applications that require bidirectional communication between clients and servers. With the knowledge gained from this tutorial, you can now explore more advanced concepts and build more sophisticated WebSocket applications.

I hope you found this tutorial helpful! If you have any questions or feedback, please leave a comment below.

Happy coding!