websockets golang

Steps to Follow to Use WebSockets in Golang

  • Web
  • November 29, 2019

We usually send a message and receive an immediate response without refreshing a page. However, earlier, allowing real-time functionality was a big challenge for app developers.

After undergoing HTTP long polling and AJAP, the community of developers has ultimately discovered a solution to develop real-time applications.

WebSockets have come as the solution to this issue and made it possible to create an interactive session between a server and browser of a user. WebSockets enable a browser to send messages to a server and get event-driven responses. And there is no need to have to poll the server for a reply.

Currently, WebSockets are the top-notch solution to develop real-time apps: tracking apps, instant messengers, online games and more.

This step-by-step guide discusses how WebSockets work and how to build WebSocket apps in the Golang language. Let’s just read on!

What are WebSockets?

WebSockets are upgraded HTTP connections that sustain until the client or the server kills the connection. Through the WebSocket connection, it is possible to perform duplex communication that is an extravagant way to say communication is possible from-and-to the server from the clients utilizing this single connection.

The best aspect of WebSockets is that they utilize one TCP connection and the entire connection is built over this single durable TCP connection.

This extremely lowers the amount of network overhead needed to develop real-time apps with the use of WebSockets since there is no continuous polling of HTTP endpoints needed.

How to Build a WebSocket App in Golang?

Here are some important steps that you must follow to write an easy WebSocket echo server depending on the net/http library:

Step-1: Setting up a handshake

At first, you need to form an HTTP handler using a WebSocket endpoint:

// HTTP server with WebSocket endpoint
        func Server() {
        http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
            ws, err := NewHandler(w, r)
            if err != nil {
                 // handle error
            }
            if err = ws.Handshake(); err != nil {
                // handle error
            }
        …

Next, run the WebSocket structure.

The client always sends the first handshake request. When the server authenticated a WebSocket request, it has to reply with a response of a handshake.

Remember that you cannot write this response with the use of http.ResponseWriter, because it will disconnect the basic TCP connection if you begin to send the response.

Hence, you have to utilize HTTP Hijacking that enables you to maintain the basic TCP connection handler and bufio.Writer. This provides you with the scope of reading and writing data without preventing the TCP connection.

// NewHandler initializes a new handler
         func NewHandler(w http.ResponseWriter, req http.Request) (WS, error) {
         hj, ok := w.(http.Hijacker)
         if !ok {
             // handle error
         }                  …..
 }

To accomplish the handshake, the server needs to respond with the relevant headers.

// Handshake creates a handshake header
    func (ws *WS) Handshake() error {
        
        hash := func(key string) string {
            h := sha1.New()
            h.Write([]byte(key))
            h.Write([]byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))

        return base64.StdEncoding.EncodeToString(h.Sum(nil))
        }(ws.header.Get("Sec-WebSocket-Key"))
      .....
}

“Sec-WebSocket-key” is randomly created and is Base64-encoded. After accepting a request, the server must add this key to a fixed string. Suppose that you have the x3JJHMbDL1EzLkh9GBhXDw== key.

In this matter, you can opt for SHA-1 for computing the binary value and Base64 for encoding it. You will receive HSmrc0sMlYUkAGmm5OPpG2HaGWk=. Utilize this as the value of the Sec-WebSocket-Accept response header.

Step-2: Transferring data frames

Once you complete the handshake, your application can read and write to and from the client. The Specification of the WebSocket describes a particular frame format that is utilized between a server and a client.

The image below showcases a little pattern of the frame:

transferring data frames

To decode the client payload, use the following code:

// Recv receives data and returns a Frame
    func (ws *WS) Recv() (frame Frame, _ error) {
        frame = Frame{}
        head, err := ws.read(2)
        if err != nil {
            // handle error
        }

In order, these code lines enable to encode data:

// Send sends a Frame
    func (ws *WS) Send(fr Frame) error {
        // make a slice of bytes of length 2
        data := make([]byte, 2)
    
        // Save fragmentation & opcode information in the first byte
        data[0] = 0x80 | fr.Opcode
        if fr.IsFragment {
            data[0] &= 0x7F
        }
        .....

Step-3: Closing a handshake

When one of the client parties sends a close frame alongside a close status as the payload, a handshake is closed.

Spontaneously, the party that sends the close frame can also send a close purpose in the payload. In case the client initiates the closing, the server must send an equivalent close frame in turn.

// Close sends a close frame and closes the TCP connection
func (ws *Ws) Close() error {
    f := Frame{}
    f.Opcode = 8
    f.Length = 2
    f.Payload = make([]byte, 2)
    binary.BigEndian.PutUint16(f.Payload, ws.status)
    if err := ws.Send(f); err != nil {
        return err
    }
    return ws.conn.Close()
}

List of WebSocket Libraries

Many third-party libraries simplify the lives of developers and amazingly aid working with WebSocket apps.

1. STDLIB (x/net/websocket)

This WebSocket library belongs to the standard library. It applies a server and client for the WebSocket protocol. You don’t need to install it and it contains good official documentation.

However, on the other hand, it doesn’t have some features that can be discovered in other WebSocket libraries. In the STDLIB (x/net/websocket) package, Golang WebSocket applications don’t enable users to use I/O buffers again between connections.

2. Gorilla

In the Gorilla web toolkit, the WebSocket package features an examined and complete application of the WebSocket protocol and a consistent package API.

This WebSocket package is easy to use and properly documented. And you can find its documentation on the official website of Gorilla.

3. GOBWAS

This is a small WebSocket package that contains a strong list of features, like a low-level API that enables to develop the logic of custom packet handling and a zero-copy upgrade. GOBWAS doesn’t need intermediate allocations during I/O.

Moreover, it features high-level helpers and wrappers around the API in the WsUtil package, enabling developers to begin quickly without examining the protocol’s internals.

Although this library comprises of a flexible API, it comes at the cost of clarity as well as usability. You can find its documentation on the GoDoc website.

4. GOWebsockets

This Golang tool provides an extensive array of easy to use features. It enables for setting request headers, compressing data, and controlling concurrency. It assists proxies and subprotocols for transmitting and getting binary data and text.

Moreover, developers can either enable or disable SSL verification. The documentation for and instances of the ways of using GOWebsockets are available on the GoDoc website.

Wrapping Up

This tutorial has covered some of the fundamentals of WebSockets and how to develop an easy WebSocket based app in Golang best tools. Besides the aforementioned tools, some other alternative applications enable developers to develop strong streaming solutions.

They include Package rpc, gRPC, Apache Thrift, and go-socket.io. The availability of properly documented tools like WebSockets and the continuous development of streaming technology make it simple for developers to build real-time apps.

Found this post insightful? Don’t forget to share it with your network!
  • facebbok
  • twitter
  • linkedin
  • pinterest
Bipin Mishra

Bipin Mishra is a Web Team Leader at MindInventory. He started his career as a PHP developer and have an expertise in AWS, GoLang, Node.js, Linux Administration, Angular, Laravel, CakePHP, CodeIgniter, ReactJS and many other back-end technology frameworks. Apart from this he is also a good backend engineer with microservices based architecture, database engineer and technical operator.