Deep Dive into WebSockets

Understand the important attributes of WebSockets that every developer should know

In the early days of the Internet, web applications were built around HTTP requests triggered by user interactions. With the advancement of technology, the requirement for real-time data transmission and two-way communication emerged. It was a requirement for low-latency applications such as,

  • Multiplayer online games
  • Chat applications
  • Realtime updating social feeds
  • Live sports scoreboards, sports tickers, etc.

The solution was WebSockets. With its wide acceptance, many libraries emerged to simplify its applications. Consequently, many of us started using the technology without knowing the internals, leading to inefficiencies.

Therefore, this article attempts to cover the essential attributes of WebSockets to reduce these gaps.

WebSockets Architecture

At its core, WebSockets defines an API that establishes a socket connection between the client and the server. It allows the web browser and the server to send data in any direction. Besides, it also comes with several optimizations compared to HTTP which makes it better for real-time communication.

Real-time Communication

With HTTP requests, the browser sends cookies and other headers using few hundreds of bytes, increasing the overhead for real-time communication.

However, with WebSockets, subsequent messages are small and only have 6 bytes of overhead (2 for the header and 4 for the mask value).

Therefore, WebSockets better suit real-time data transmission and is especially suited for low-latency applications as the overhead is less.

WebSocket Connection

Opening a WebSocket connection is straightforward. If you need to specify the subprotocols, that can be done as well using a second parameter.

https://medium.com/media/60069652413e906be4f1b0a337c0046f/href

Once the socket connection is created, you can attach event handlers to it which allows you to know when the connection is opened, when it receives messages and when there is an error.

https://medium.com/media/6fbe6dc90c6927843bea91d7274d66f3/href

Once the connection is established, the onopen event will be fired on the WebSocket instance. And this marks the completion of the handshake. From this point onwards either party can send data anytime. When the WebSocket is receiving data on the client-side, the onmessage event is fired. The onerror event can be used to handle errors.

You might wonder, what’s new about this? Isn’t that we always do, creating a connection and listen to messages?

With WebSockets, it’s important how we handle the connection.

How we handle the connection and retry on connection errors will also determine the overall fault-tolerance of the communication.

Connection Retry for Fault-Tolerance

A common issue when working with WebSockets is broken connections. This occurs when either the client or server does not respond. To avoid any issues due to this, you should implement a mechanism to gracefully close the connection. Especially if the WebSocket connection life is long, a method to refresh connections (close and open connections again) from time to time, needs to be implemented to have a smooth communication system.

Scaling the Connections

Since WebSockets require high availability due to the persistent connections, the server should be scalable to cater to the high demand when needed. However, after a ws connection is opened, most of the time, it would be idle.

Therefore, you might wonder how we should scale the Websocket backend?

Scaling the WebSocket backend is a complex task that will require persistent storage (Also known as a backplane) to keep track of the connections and delivered messages if any server node goes down.

Besides, it would be best to implement a scale-out strategy, considering the number of open connections.

Since most users might not re-connect often, improving scalability based on open connections makes much more sense.

Tip: Share your reusable components between projects using Bit (Github).

Bit makes it simple to share, document, and reuse independent components between projects. Use it to maximize code reuse, keep a consistent design, speed-up delivery, and build apps that scale.

Bit supports Node, TypeScript, React, Vue, Angular, and more.

Example: exploring reusable React components shared on Bit.dev

Data Transfer Patterns

There are different patterns you could consider when transferring data via Web Sockets. You could either transmit the message directly through WebSockets or send a notification to the client mentioning the message’s availability.

WebSockets to send notifications for web apps

Sending in-app notifications is a common use case for WebSockets. The WebSocket connection is used only to alert the browser that a new message is available.

Once the user receives the notification and visits the notifications page, the application can send an HTTP request to retrieve the message content.

So in this approach, WebSocket doesn’t send the actual message content and is used as a signaling mechanism to inform the notification availability to the frontend.

Using WebSockets for real-time data transfer

For real-time multi-player games or chat applications, the data needs to be sent without a delay as there is an active user always looking at the screen waiting for data.

In this scenario, we can send the message data directly through a WebSocket connection for faster message delivery.

Data Compression

With WebSockets, compression isn’t a topic that is often discussed. But if large amounts of data need to be sent in real-time, using an approach for compression is useful.

However, to achieve data compression with WebSockets, both the client and server need to agree on this.

Did you know that WebSockets provides an extension for data compression?

When the client initiates the negotiation by advertising the permessage-deflate extension in the Sec-Websocket-Extensions header, the server must confirm the advertised extension by echoing it in its response.

Client initiation:

GET /socket HTTP/1.1
Host: thirdparty.com
Origin: http://example.com
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Extensions: permessage-deflate

Server response:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Access-Control-Allow-Origin: http://example.com
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Extensions: permessage-deflate

Web Sockets Security

WebSockets allow an unlimited number of messages to reach the server. This can easily give an attacker access to perform a DoS attack.

Therefore, it is essential to use an authentication mechanism to enforce security. One of the common usages is to use JWT tokens which makes it faster to verify the request’s signature.

Furthermore, it’s vital to use wss instead of ws, which will secure the communication tunnel, similar to HTTPS.

Browser Compatibility

WebSockets have good browser compatibility with almost all the browsers.

Source: caniuse.com

Also, WebSockets have built-in cross-origin communication. It enables communicating with any party on any domain. This can be controlled by defining the domains that the server can communicate with, which increases security.

Besides, popular WebSockets implementations such as socket.IO (NodeJS) or SignalR (.NET) support fallback to HTTP in older browsers.

Conclusion

Whenever you need a better low-latency connection between a client and server, WebSockets is your best option.

However, WebSockets can be frustrating to integrate into your existing web infrastructure as it requires a change in architecture. Besides, you could also look at the Event Sourcing pattern, which effectively uses WebSockets for communication.

Let me know any further details that you would like to know about WebSockets in the comments below. You can check out a WebSocket connection demo here.

Thanks for reading.

Learn More

Build a Realtime Editor Using Socket.IO


Deep Dive into WebSockets was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.

Understand the important attributes of WebSockets that every developer should know

In the early days of the Internet, web applications were built around HTTP requests triggered by user interactions. With the advancement of technology, the requirement for real-time data transmission and two-way communication emerged. It was a requirement for low-latency applications such as,

  • Multiplayer online games
  • Chat applications
  • Realtime updating social feeds
  • Live sports scoreboards, sports tickers, etc.

The solution was WebSockets. With its wide acceptance, many libraries emerged to simplify its applications. Consequently, many of us started using the technology without knowing the internals, leading to inefficiencies.

Therefore, this article attempts to cover the essential attributes of WebSockets to reduce these gaps.

WebSockets Architecture

At its core, WebSockets defines an API that establishes a socket connection between the client and the server. It allows the web browser and the server to send data in any direction. Besides, it also comes with several optimizations compared to HTTP which makes it better for real-time communication.

Real-time Communication

With HTTP requests, the browser sends cookies and other headers using few hundreds of bytes, increasing the overhead for real-time communication.

However, with WebSockets, subsequent messages are small and only have 6 bytes of overhead (2 for the header and 4 for the mask value).

Therefore, WebSockets better suit real-time data transmission and is especially suited for low-latency applications as the overhead is less.

WebSocket Connection

Opening a WebSocket connection is straightforward. If you need to specify the subprotocols, that can be done as well using a second parameter.

Once the socket connection is created, you can attach event handlers to it which allows you to know when the connection is opened, when it receives messages and when there is an error.

Once the connection is established, the onopen event will be fired on the WebSocket instance. And this marks the completion of the handshake. From this point onwards either party can send data anytime. When the WebSocket is receiving data on the client-side, the onmessage event is fired. The onerror event can be used to handle errors.

You might wonder, what’s new about this? Isn’t that we always do, creating a connection and listen to messages?

With WebSockets, it's important how we handle the connection.

How we handle the connection and retry on connection errors will also determine the overall fault-tolerance of the communication.

Connection Retry for Fault-Tolerance

A common issue when working with WebSockets is broken connections. This occurs when either the client or server does not respond. To avoid any issues due to this, you should implement a mechanism to gracefully close the connection. Especially if the WebSocket connection life is long, a method to refresh connections (close and open connections again) from time to time, needs to be implemented to have a smooth communication system.

Scaling the Connections

Since WebSockets require high availability due to the persistent connections, the server should be scalable to cater to the high demand when needed. However, after a ws connection is opened, most of the time, it would be idle.

Therefore, you might wonder how we should scale the Websocket backend?

Scaling the WebSocket backend is a complex task that will require persistent storage (Also known as a backplane) to keep track of the connections and delivered messages if any server node goes down.

Besides, it would be best to implement a scale-out strategy, considering the number of open connections.

Since most users might not re-connect often, improving scalability based on open connections makes much more sense.

Tip: Share your reusable components between projects using Bit (Github).

Bit makes it simple to share, document, and reuse independent components between projects. Use it to maximize code reuse, keep a consistent design, speed-up delivery, and build apps that scale.

Bit supports Node, TypeScript, React, Vue, Angular, and more.

Example: exploring reusable React components shared on Bit.dev

Data Transfer Patterns

There are different patterns you could consider when transferring data via Web Sockets. You could either transmit the message directly through WebSockets or send a notification to the client mentioning the message’s availability.

WebSockets to send notifications for web apps

Sending in-app notifications is a common use case for WebSockets. The WebSocket connection is used only to alert the browser that a new message is available.

Once the user receives the notification and visits the notifications page, the application can send an HTTP request to retrieve the message content.

So in this approach, WebSocket doesn’t send the actual message content and is used as a signaling mechanism to inform the notification availability to the frontend.

Using WebSockets for real-time data transfer

For real-time multi-player games or chat applications, the data needs to be sent without a delay as there is an active user always looking at the screen waiting for data.

In this scenario, we can send the message data directly through a WebSocket connection for faster message delivery.

Data Compression

With WebSockets, compression isn’t a topic that is often discussed. But if large amounts of data need to be sent in real-time, using an approach for compression is useful.

However, to achieve data compression with WebSockets, both the client and server need to agree on this.

Did you know that WebSockets provides an extension for data compression?

When the client initiates the negotiation by advertising the permessage-deflate extension in the Sec-Websocket-Extensions header, the server must confirm the advertised extension by echoing it in its response.

Client initiation:

GET /socket HTTP/1.1
Host: thirdparty.com
Origin: http://example.com
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Extensions: permessage-deflate

Server response:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Access-Control-Allow-Origin: http://example.com
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Extensions: permessage-deflate

Web Sockets Security

WebSockets allow an unlimited number of messages to reach the server. This can easily give an attacker access to perform a DoS attack.

Therefore, it is essential to use an authentication mechanism to enforce security. One of the common usages is to use JWT tokens which makes it faster to verify the request's signature.

Furthermore, it’s vital to use wss instead of ws, which will secure the communication tunnel, similar to HTTPS.

Browser Compatibility

WebSockets have good browser compatibility with almost all the browsers.

Source: caniuse.com

Also, WebSockets have built-in cross-origin communication. It enables communicating with any party on any domain. This can be controlled by defining the domains that the server can communicate with, which increases security.

Besides, popular WebSockets implementations such as socket.IO (NodeJS) or SignalR (.NET) support fallback to HTTP in older browsers.

Conclusion

Whenever you need a better low-latency connection between a client and server, WebSockets is your best option.

However, WebSockets can be frustrating to integrate into your existing web infrastructure as it requires a change in architecture. Besides, you could also look at the Event Sourcing pattern, which effectively uses WebSockets for communication.

Let me know any further details that you would like to know about WebSockets in the comments below. You can check out a WebSocket connection demo here.

Thanks for reading.

Learn More

Build a Realtime Editor Using Socket.IO


Deep Dive into WebSockets was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.


Print Share Comment Cite Upload Translate
CITATION GOES HERE CITATION GOES HERE
Select a language: