Mohit Khare I'm a developer soul and a freelance writer from India who loves building and breaking stuff. Let's build something together!

Using WebSockets in Go

4 min read 1243

Using WebSockets Go

In the modern digital age, users expect information to be processed instantly. Lags and buffering can have severe consequences for your UX, regardless of the type of application.

In the past, sending and receiving messages using methods like HTTP polling was a real challenge. Blocks on the server caused delays and frustrations for developers and users alike. However, the release of WebSockets in 2008 introduced an effective and simple solution for building real-time apps.

In this article, we’ll learn how to implement a to-do app using WebSockets in Go. We’ll explore WebSockets in-depth, set up WebSockets for Go, and finally, explore some use cases for WebSockets.

If you’re new to Go, I recommend getting familiar with web servers in Go first. Let’s get started!

What are WebSockets?

WebSockets are a communications protocol that use full-duplex communication channels over a single durable Transmission Control Protocol (TCP) connection.

With full-duplex communication, both the server and the client can transmit and receive data simultaneously without being blocked, reducing overhead in comparison to alternatives that use half-duplex communication like HTTP polling.

With less overhead, WebSockets enable real-time communication and rapid data transferring between the web server and the web browser or client application. WebSocket communication initiates a handshake, which uses the HTTP Upgrade() header to change from the HTTP protocol to the WebSocket protocol.

Data can be transferred from the server without a prior request from the client, allowing messages to be passed back and forth and keeping the connection open until the client or server kills it. Thus, a two-way real-time data transfer can take place between the client and the server. WebSocket communications are usually done via TCP port number 443.

The WebSocket protocol specification defines two URI schemes:

  • WebSocket (ws): used for non-encrypted connections
  • WebSocket Secure (wss): used for encrypted connections

WebSocket Protocol Specification Diagram

We made a custom demo for .
No really. Click here to check it out.

Let’s explore each step in building an app using WebSockets.

Setting up the HTTP server

WebSockets are built on top of HTTP, so first, we’ll set up a basic HTTP server that can accept client connections and serve messages. Add the following code to your server.go file:

package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Setting up the server!")
    })
    http.ListenAndServe(":8080", nil)
}

Start the server by running go run server.go. When you visit localhost:3000, you should see the following output:

Setting up the server!

Initiating a handshake

To set up a WebSocket connection, a one-time handshake is required between the client and the server. A handshake uses the Upgrade() method to upgrade the HTTP server connection to the WebSocket protocol. We’ll also use defer to close the connection once the server is stopped.

Let’s modify our server.go file to set up a WebSocket handshake:

Note: The client must send the first handshake request. Then, the server can authenticate this WebSocket request and reply to the client with an appropriate response.

conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Print("upgrade failed: ", err)
return
}
defer conn.Close()

Setting up our to-do app

Now that we have a basic app set up in WebSockets, let’s add features for adding and completing a task. We’ll set up these two commands in our app from the client, and in response to the commands, we’ll send the current to-do list.

First, we’ll add a web template and set up our client to request the connection and send messages to the server. We’ll use a simple HTML file with a script that creates a socket connection.

As you build your application further, you can move your JavaScript code out to a separate file. We’ll add the following code to websockets.html:

<html>
  <div>
    <h1>Go websockets TODO example</h1>
    <p>Available commands for todo app</p>
    <p>- add [task]</p>
    <p>- done [task]</p>
    <input id="input" type="text" size="40" />
    <button onclick="send()">Send</button>
    <pre id="output"></pre>
  </div>
  <style>
    html {
      text-align: center;
      font-size: 16px;
    }
    div {
      padding: 1rem;
    }
    #input {
      font-size: 16px;
    }
    p {
        font-size: 16px;
    }
  </style>
  <script>
    var input = document.getElementById("input");
    var output = document.getElementById("output");
    var socket = new WebSocket("ws://localhost:8080/todo");

    socket.onopen = function () {
      output.innerHTML += "Status: Connected\n";
    };

    socket.onmessage = function (e) {
      output.innerHTML += "\nServer: " + e.data + "\n";
    };

    function send() {
      socket.send(input.value);
      input.value = "";
    }
  </script>
</html>

Now that our client is ready, let’s update our handler to manage the functionality of our to-do app.
We’ll add commands add and done for completing a task. The to-do handler will also respond with the current state of our to-do list.

Copy the following code into server.go:

package main

import (
    "log"
    "net/http"
    "strings"

    "github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{}
var todoList []string

func getCmd(input string) string {
    inputArr := strings.Split(input, " ")
    return inputArr[0]
}

func getMessage(input string) string {
    inputArr := strings.Split(input, " ")
    var result string
    for i := 1; i < len(inputArr); i++ {
        result += inputArr[i]
    }
    return result
}

func updateTodoList(input string) {
    tmpList := todoList
    todoList = []string{}
    for _, val := range tmpList {
        if val == input {
            continue
        }
        todoList = append(todoList, val)
    }
}

func main() {

    http.HandleFunc("/todo", func(w http.ResponseWriter, r *http.Request) {
        // Upgrade upgrades the HTTP server connection to the WebSocket protocol.
        conn, err := upgrader.Upgrade(w, r, nil)
        if err != nil {
            log.Print("upgrade failed: ", err)
            return
        }
        defer conn.Close()

        // Continuosly read and write message
        for {
            mt, message, err := conn.ReadMessage()
            if err != nil {
                log.Println("read failed:", err)
                break
            }
            input := string(message)
            cmd := getCmd(input)
            msg := getMessage(input)
            if cmd == "add" {
                todoList = append(todoList, msg)
            } else if cmd == "done" {
                updateTodoList(msg)
            }
            output := "Current Todos: \n"
            for _, todo := range todoList {
                output += "\n - " + todo + "\n"
            }
            output += "\n----------------------------------------"
            message = []byte(output)
            err = conn.WriteMessage(mt, message)
            if err != nil {
                log.Println("write failed:", err)
                break
            }
        }
    })

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        http.ServeFile(w, r, "websockets.html")
    })

    http.ListenAndServe(":8080", nil)
}

Now, run your server, and you should see the working to-do app on localhost:8080. Feel free to add new items to personalize your to-do list.

After adding and completing a couple of tasks, the to-do app should look like the following screenshot:

Final Go Websocket To Do App

Use cases for WebSockets

WebSockets’ primary purpose is to support full-duplex, or two-way communication. In addition to providing real-time updates, WebSockets include a single, lightweight server that can support multiple open WebSocket connections. WebSockets can sustain the connection between the client and server over a longer period of time than most other methods.

Currently, WebSockets offers cross-platform support for Android, iOS, web, and desktop applications, and WebSockets are commonly used in the following types of applications:

  • Real-time messaging
  • Multiplayer gaming
  • Live score feeds
  • Collaborative editing tools
  • Live location and direction apps
  • Audio and video chat using WebRTC

Summary

In this article, we explored WebSockets with a brief introduction on how they work, looking closely at full-duplex communication. To understand how WebSockets work in Go, we built a simple to-do application with features for adding and removing tasks. Finally, we looked at several additional features that make WebSockets useful and versatile, and reviewed some practical applications of WebSockets.

Using WebSockets in Go is fairly simple and straightforward, but this combination can have dramatic results on your application’s performance.

: Full visibility into your web apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.
Mohit Khare I'm a developer soul and a freelance writer from India who loves building and breaking stuff. Let's build something together!

Testing accessibility with Storybook

One big challenge when building a component library is prioritizing accessibility. Accessibility is usually seen as one of those “nice-to-have” features, and unfortunately, we’re...
Laura Carballo
4 min read

One Reply to “Using WebSockets in Go”

  1. Great article but I noticed you have a typo.

    I first code example you use port 8080
    http.ListenAndServe(“:8080”, nil)

    but when suggest testing you have
    localhost:3000

Leave a Reply