WebSocket EP 1 - The Hidden Mechanics of the Protocol
Hi Devs! I’ve been building REST APIs for the past 2 years. But now I want to learn about real-time communications, and I’ve decided to dive deep into WebSockets. I’ll be publishing a series of blog posts about WebSocket, and this is the 1st part of that series. At the end of the series, we will make a real-time multiplayer tic-tac-toe game, or if my dopamine hits me hard in the upcoming days, we will also make a multiplayer game server.
Below are the next planned articles:
Authentication, Authorization & Security Pitfalls in WebSocket Apps
Building Production-Grade Real-Time Apps
Binary, Protocols, and Advance Patterns WebSocket
Scalability War Stories: How Real-Time Systems Stay Alive
What are WebSockets?
WebSockets are a very powerful real-time communication protocol that allows bi-directional communication between client and server on a single TCP connection. It was developed by Ian Hickson and Michael Carter in 2008 because HTTP is not good enough for real-time communication.
Where and how WebSockets are used?
Let’s suppose it’s 2006. You are in front of your computer screen looking for stock prices. In order to get instant updates about prices, you are aggressively refreshing the page. With each refresh a new HTTP request is going to the server and bringing back updated stock data for you.
What if there is a way which allows you to see real-time updated data without refreshing the page? That’s what WebSocket does. Instead of the traditional request-response model where the connection is closed once data is fetched, WebSocket keeps the connection alive and keeps delivering data. Which leads to real-time communication and data transfer.
Some other use cases of WebSockets may include:
Multiplayer Gaming
Chat Application
Live Dashboards
Live Sports Data
and whatever realtime stuff you can think of.
How to initiate a WebSocket connection?
WebSocket uses HTTP to initiate a connection. At first a new HTTP connection is created, and then it is upgraded to a WebSocket connection with the help of specific request headers.
At this point I’m assuming that you already know what HTTP is and how it works. Because HTTP will be used to establish a WebSocket connection. In case you don’t know what HTTP is, I highly recommend reading this article by Cloudflare.
In order to start a WebSocket connection we have to make a HTTP Get request to the server with following request headers.
Sec-WebSocket-Version: Indicates which version of WebSocket is being used. Version 13 is the standardized and most widely supported version as defined by RFC 6455.
Sec-WebSocket-Key: A base64-encoded random key generated by the client. It is used to verify that a client intends to establish a WebSocket connection.
Connection: Indicates that the client wants to change the current HTTP connection to a different protocol.
Upgrade: Specifies the protocol to upgrade to — in this case, websocket.
Sec-WebSocket-Extensions: Specifies optional WebSocket extensions the client wants to use. We are using compression extension here.
Server Response:
If the server successfully establishes a WebSocket connection, it will also respond with specific response headers.
Upgrade & Connection headers are familiar to us.
Sec-WebSocket-Accept: This header contain base64 encoded hash of Sec-WebSocket-Key (which we sent with request) and a universally unique identifier.
If the server responded with a response like shown above, our WebSocket connection is created. Let us now write some code and create a connection practically.
Let’s Write Code
All the code here is in GoLang, but you can easily find WebSocket implementations in any language if you want.
Here is the basic stuff. I’m importing several packages. “fmt” for logging, “net/http” for creating an HTTP server and “gorilla/websocket” for upgrading an HTTP connection to WebSocket.
One thing to note is that we are not going to manually write code to upgrade HTTP Connection to WebSocket. That will be a very complex process, and you will need to write a complete WebSocket protocol on your own.
Every language or framework will always provide you tools to directly work with WebSockets.
First, I’ve created a function that will get the HTTP request and response writer as parameters. This is GoLang-specific stuff. But it is the same in most languages.
After that I’m creating a WebSocket. Upgrade struct from the gorilla/websocket package. This struct will act as a configuration. Currently I’ve defined the amount of data that can be read (1024 bytes in my case).
Then I’m passing the HTTP request and writer to the upgrade method, which will convert our connection to HTTP.
Now we have a fully functional WebSocket connection established, and we can read and write messages.
The above code will print the message coming from the client and write the same message to the client.
Finally I’m starting a HTTP server.
WebSocket in Action:
Okay! Now let’s test this stuff. I’ll open Postman and start a new WebSocket connection to “ws://localhost:3000/ws”.
Below is the response that we got after a successful WebSocket connection.
After that I sent some data to our WebSocket connection. The up arrow shows data sent from Postman, and the down arrow shows data we received.
Below is a screenshot from server terminal.
Our code is written to do 2 things:
Print data coming from the client.
Write back the same data to the client.
That’s why we are able to see the same data twice in Postman. Hence, we achieved real-time communication via WebSockets.
Can we do simple HTTP request to WebSocket endpoint?
I’ve a question for you. What if we do a simple HTTP request to WebSocket without sending WebSocket-specific headers? What will happen? Can we connect?
If your answer is NO!, you are right. HTTP is used just to initiate a WebSocket connection by upgrading the protocol. If we do a normal HTTP request, the protocol will never be upgraded, and we will get a bad request error.
Let’s see this in action.
In the above screenshot, when I hit the WebSocket endpoint via the browser, we are getting a bad request. If you see the Network tab, you can see that our browser never sent connection upgrade headers.
Other Articles
Writing Load Balancer - Beginner Friendly
Let’s Be Friends
Upcoming Parts
This was the 1st part of this series. In upcoming parts we are going to deep dive into WebSockets, and the next post will be related to security in WebSockets.
You can subscribe to my newsletter and receive that in your inbox in real time.