WebSockets in Go and GoFr

Umang Mundhra - Jun 28 - - Dev Community

The Evolution of Real-Time Communication: A Brief History

WebSockets in Go and GoFr

In the early days of web development, achieving real-time communication between clients and servers was a challenge. Developers had to rely on methods like HTTP polling, which often caused blocks on the server, leading to delays and frustrations for both developers and users. This method involved repeatedly asking the server if there were any updates, which was inefficient and resource intensive. Then came HTTP long polling and AJAX which improved the situation but still had limitations, especially in building truly real-time applications. The real breakthrough came in 2008 with the introduction of WebSockets. This innovative technology provided an effective and straightforward solution for real-time communication. WebSockets revolutionized the way we build real-time apps, making it easier and more efficient to create dynamic, interactive web applications.


What are WebSockets?

WebSocket is a computer communications protocol that provides full-duplex communication channels over a single TCP connection. Unlike HTTP polling, which uses half-duplex communication, WebSocket allows both the server and the client to transmit and receive data simultaneously without being blocked. This reduces overhead and provides a more efficient way to maintain a continuous connection between the client and server. 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.

WebSockets can sustain a connection for a longer period than most other methods, enabling real-time data transfer and keeping the connection open until either the client or server terminates it. Detailed information about the WebSocket protocol can be found in the Internet Engineering Task Force (IETF) RFC 6455 specification.

WebSocket Use-Cases and Examples:

WebSockets enjoy widespread support across platforms like Android, iOS, web browsers, and desktop applications. This versatility makes them a valuable tool for building real-time features across devices. Here are some real-world use case examples for websockets:

  • WhatsApp Web: Connects to your phone via WebSockets, enabling instant messaging, status updates, and real-time interactions.

  • GitHub Pull Requests: WebSockets keep the conversation open, allowing real-time updates on comments and changes without page refreshes.

  • Real-Time Tracking Applications: Ride-sharing and delivery apps leverage WebSockets for real-time location updates on drivers or deliveries.

  • Stock Tickers and Financial Dashboards: WebSockets facilitate displaying live stock prices and real-time updates on financial dashboards.

  • Audio/Video Chat (WebRTC): WebSockets play a role in enabling real-time audio and video communication through WebRTC technology.


WebSockets vs. HTTP: Understanding the Contrastst

Both HTTP and WebSockets are communication protocols that facilitate data exchange between a client and a server. However, they serve distinct purposes and operate in fundamentally different ways.
HTTP (Hypertext Transfer Protocol) follows a well-established request-response cycle. The client initiates a request, the server processes it, and sends a response back to the client. HTTP connections are short-lived. Each request establishes a connection, the server sends a response, and the connection closes. Each request from a client to the server is independent of any previous requests. This statelessness simplifies the design of web servers but can make certain types of communication inefficient. HTTP messages consist of headers and a body. The headers contain metadata about the message (such as content type and length), while the body contains the actual data being transferred.

WebSockets establish a persistent, two-way connection between client and server. Both parties can send and receive data simultaneously, enabling real-time data flow. Unlike HTTP's short-lived connections, WebSockets remain open until either client or server terminates them. This persistent connection facilitates efficient real-time communication. Data can be sent from server to client without prior client requests, enabling immediate updates and interactions.
In essence, HTTP excels at reliable request-response communication for static content retrieval. WebSockets, on the other hand, shine in real-time scenarios where continuous two-way data exchange is crucial.


How WebSockets Work: Behind the Scenes of Real-Time Communication

WebSockets start as a standard HTTP request and response, but then transition into a persistent, full-duplex communication channel. Here's how this process unfolds:

1. The WebSocket Connection Open Handshake

WebSocket URIs use the scheme ws: (or wss: for a secure WebSocket). The structure of the URI is similar to an HTTP URI, consisting of a host, port, path, and any query parameters. The connection begins with the client initiating an HTTP GET request with specific headers, including:
Upgrade: This header is set to websocket.
Sec-WebSocket-Key: This header contains a randomly generated base64 encoded key.

The server responds to this request. If it is able to upgrade the connection, it sends back a response with an HTTP 101 Switching Protocols status code, indicating that it is switching to the WebSocket protocol as requested. This response includes headers such as:
Upgrade: Confirming the upgrade to websocket.
Sec-WebSocket-Accept: A base64 encoded string, which is the server's response to the client's Sec-WebSocket-Key.

Once this handshake is successfully completed, the connection is upgraded, and both client and server switch to the WebSocket protocol.

2. The WebSocket Protocol

WebSocket is a framed protocol, which means that data is sent in discrete chunks called frames. Each frame consists of a header and a payload. The header contains information about the frame, including:
Opcode: This field indicates the type of frame (e.g., text, binary, control).
Payload Length: This field specifies the size of the payload.
Fragmentation Information: This indicates whether the frame is part of a larger message.

The frames are categorized by their opcode into types such as text frames, binary frames, and control frames (for connection management). This structure allows both the client and the server to interpret and process the data efficiently.

3. Closing the connection

To close a WebSocket connection, a closing frame is sent (opcode 0x08). In addition to the opcode, the close frame may contain a body that indicates the reason for closing. If either side of a connection receives a close frame, it must send a close frame in response, and no more data should be sent over the connection. Either party can initiate closing the connection by sending a Close control frame with a specific status code (e.g., 1000 for normal closure). Once the close frame has been received by both parties, the TCP connection is torn down. The server always initiates closing the TCP connection.

Working of websockets


Using WebSockets in Go and GoFr:

What is GoFr?

GoFr is a comprehensive Golang framework designed to simplify web application development by providing a rich set of features, including built-in support for WebSockets. This makes it easy to build real-time applications with minimal setup and configuration.

Getting Started with GoFr WebSockets:

Using GoFr WebSockets is straightforward. Here's the basic flow:
Define a WebSocket Handler: Create a function to handle incoming WebSocket connections. This function will receive messages from the client and can send responses back.

Register the Handler with GoFr: Use the app.WebSocket method to associate your handler function with a specific endpoint (URL path) on your GoFr application.

That's it! GoFr takes care of the underlying WebSocket handshake and message framing, allowing you to focus on your application logic.
Let's Code:

package main

import (
 "fmt"

 "gofr.dev/pkg/gofr"
)

type Message struct {
 Content string `json:"content"`
 User    string `json:"user"`
}

func main() {
 app := gofr.New()

 app.WebSocket("/chat", ChatHandler)

 app.Run()
}

func ChatHandler(ctx *gofr.Context) (interface{}, error) {
 // Read the incoming message from the client
 var message Message
 err := ctx.Bind(&message)
 if err != nil {
  return nil, err
 }

 // Process the message (e.g., broadcast to all connected clients, save it to a database, etc.)
 ctx.Infof("Received message from %s: %s\n", message.User, message.Content)

 // You can send data back to the client here (optional)

 return nil, nil
}
Enter fullscreen mode Exit fullscreen mode

In this example, We define a Message struct to represent chat messages. The ChatHandler function reads the incoming message using ctx.Bind. GoFr automatically detects the message format (JSON in this case) and unmarshals it into the Message struct. You can process the received message (e.g., broadcast it to all connected clients). Sending data back to the client is also possible within the handler function.

When you run the above code and try to send a message to the server using Postman:

Sending message to server using WebSocket

You get these logs at the console where GoFr server is running:

Terminal logs showing successful message receival


Conclusion

In this article, we delved into the evolution of real-time communication from the days of HTTP polling to the modern era of WebSockets. We explored the fundamental differences between HTTP and WebSocket protocols, emphasizing how WebSockets provide a robust solution for real-time, bidirectional communication.
WebSockets have become an essential tool for building dynamic and responsive applications, from chat applications and real-time notifications to live updates and beyond. With GoFr, you have the tools to leverage this technology efficiently, ensuring your applications are both performant and maintainable.
We encourage you to explore GoFr and its WebSocket capabilities further, as it can significantly enhance your development experience and the performance of your real-time applications.

Do checkout GoFr and it's Github Repo and support it by giving it a ⭐.

Example Code Link: https://github.com/Umang01-hash/Medium-Articles/tree/main/WebSockets

Thank you for reading, Happy coding,!

. .