Web Sockets have become a fundamental technology in modern web development, but their true function is often misunderstood. The killer use-case for Web Sockets has been in the development and proliferation of chat apps where users jump into a channel and write messages to one another. This has led to a wide spread understanding that Web Sockets provide publish and subscribe capability for your application - but this is a myth - Web Sockets do not Pub-Sub. In this article you will learn about Web Sockets, what they do and how they fit into your application architecture and common uses for Web Sockets in web application development.
What are Web Sockets?
Web Sockets represent a communication protocol that creates a persistent connection between a client (typically a web browser) and a server. Unlike traditional HTTP, which follows a request-response pattern, Web Sockets allow:
- Two-way communication: Both server and client can send messages at any time
- Persistent connection: One connection stays open instead of creating new ones for each interaction.
- Low latency: Messages transmit immediately without the overhead of establishing new connections
Before Web Sockets, developers used techniques like HTTP polling, where browsers would repeatedly ask servers "Do you have anything new for me?". This is inefficient and causes delays. Web Sockets solved this problem by creating a direct communication channel that stays open enabling servers to send data directly to clients as soon as it is available which enables powerful real-time bi-directional communication.
How Web Sockets Work?
WebSocket connections are an instance of an upgraded standard HTTP connection over TCP. When connecting to a web server with the “wss” protocol - the server attempts to upgrade the connection from a standard HTTP web connection to a persistent websocket one.
This process happens in two main phases:
The Handshake
When a client wants to establish a WebSocket connection:
- Initial Request: The client sends an HTTP request that says "I'd like to upgrade this connection to Web Sockets" and ”I support these sub-protocols”.
- Server Verification: The server responds with a special code confirming it accepts the WebSocket connection and also confirms the sub-protocol it prefers the client to use.
- Connection Established: Once the handshake completes successfully, the HTTP connection "upgrades" to a WebSocket connection.
This handshake is designed to be compatible with HTTP infrastructure, so Web Sockets can work on standard web ports (80 and 443).
Data Transfer
After the connection is established:
- Data is sent in units called "frames".
- Messages can be text (UTF-8) or binary data.
- Either side can send messages at any time and messages must conform to the agreed sub-protocol.
- For security, all client-to-server messages are encrypted over the TSL channel created when connecting.
- The connection stays open until either side decides to close it.
It is important to understand that with a Web Socket connection both the client and server are able to send messages to the other at anytime. Any data written to the Web Socket will be transported to the other party. This is where sub-protocols become important and are a critical component of the design process for an application leveraging this technology. The way clients and servers communicate over Web Sockets is defined by the sub-protocol.
What are SubProtocols?
Subprotocols are agreed-upon conventions for how messages should be formatted and interpreted. Think of them as languages that both client and server agree to speak. Sub-protocols are important for:
- Standardization: Provide consistent ways to format messages (like JSON, XML, or custom formats)
- Messaging Syntax: provides the order and meaning of messages and defines any request/response style interactions and how these are tracked. If you are using web-sockets to transfer request/response interactions these need to be carefully thought out and designed so the client and server can correlate related messages.
- Versioning: Allows protocols to evolve while maintaining backward compatibility
- Interoperability: Different implementations can work together if they follow the same subprotocol
During the handshake, the client can say "I can speak these sub-protocols" and the server responds with "Let's use this one." For example:
- A chat application might use a chat-specific sub-protocol.
- A financial application might use a different sub-protocol optimized for market data.
- A game might use yet another sub-protocol designed for real-time player movements.
By eliminating the constant request-response cycle and providing a direct communication channel, Web Sockets make interactive web applications more responsive and efficient, especially when real-time updates are essential.
Where is the Pub-Sub?
The Web Sockets layer itself doesn’t provide any capability or functionality other than handling the client connections and transferring data between the client and server applications that sit at either end of the data pipe connection (Web Socket).
The connections starts as a normal HTTP connection with DNS Lookup and TLS handshake for a secure connection. Once the HTTP connection is complete the client will send a standard HTTP get asking to upgrade the connection to a websocket. It is at this point the client will include a list of sub-protocols it understands. The server provides the client sub-protocols and asks the backend server to authorize the connection. The backend server will respond with the sub-protocol is prefers to use from those provided by the client and whether the connection is authorized to continue.
It is at this point that the connection is now established and either the client or server are able to send data to each other using the selected sub-protocol. The client is able to send a message conforming to the sub-protocol syntax to the server for processing. Periodically the Web Socket server may send keep-alive messages which are documented as part of the Web Socket protocol - these "Ping"-"Pong" messages are a way to ensure the connection is healthy.
Web Sockets, being bi-directional, enables the server to also send notifications to the client. These can occur at anytime and the client decides how to handle these. The sub-protocol determines the structure of data to be sent between the client and server and it also dictates how each actor will respond to messages being sent.
When the client and server communications are complete, either may request to close down the connection and disconnect.
Web Sockets do not provide any functionality other than transporting data between client and server applications, it is the backend server implementation which provides the Publish and Subscribe capability. For this reason it is essential to think about the sub-protocol your applications will use when communicating over web-sockets, without this you will have applications sending garbage to one another and not achieving anything useful.
Considerations for Architects and Developers
Web Sockets provide the core communications capability for realtime data transfer, they handle the establishment of the connection and transfer of data. From a client-server application perspective there are a number of challenges that Architects and Developers need to be aware of when designing and building solutions around Web Sockets.
Connection Management
Unlike stateless HTTP, WebSocket connections create long-lived connections that must be actively managed. Networks are often unreliable with interruptions causing connections to drop. When you build with Web Sockets both the client and server developers must be mindful of the connections and their state - the management required is dependent on the actual features and function of the application sub-protocol being implemented. You will need to consider the following for managing connections:
- Implementing reconnection logic with exponential backoff on both client and server
- Design for graceful handling of unexpected disconnections.
- Consider connection monitoring with Ping/Pong frames to detect "zombie" connections.
- Ensure both client and server can detect "half-open" connections where TCP remains connected but the application level communication has failed.
- Handle abrupt disconnect from clients which can occur through application crashes or browser tab closure or refresh scenarios to ensure you have clean disconnection logic.
Message Ordering and Delivery Guarantees
Web Sockets guarantee in-order delivery on a single connection but lack mechanisms for handling reconnection scenarios. When clients are reconnecting you need to consider the following:
- Implement application-level sequence numbers for all messages to detect missed updates.
- Build acknowledgment protocols for critical messages with timeout-based retransmission.
- Design idempotency into message handling to safely process potential duplicates during reconnection.
- Consider queuing unacknowledged messages for retransmission after re-establishing the Web Socket connection.
State Synchronization after Disruption
Web Sockets do not provide delivery guarantees or a way to rebuild state following a disconnection. When connections drop, there is no built-in way to determine what state was lost. You will need to consider designing a mechanism to deal with these scenarios:
- Design efficient delta synchronization protocols to minimize data transfer after reconnection.
- Consider event sourcing approaches where clients can request specific missed events.
- Build "catchup" mechanisms that determine precisely what updates a reconnecting client needs.
Resource Management and Throttling
Web Sockets lack built-in flow control beyond TCP's mechanisms. This places the burden of resource management and throttling on you as a service provider. You need to consider the following:
- Implement application-level back pressure signals when receivers can't keep up with message volume
- Design rate-limiting systems that account for both message frequency and payload size
- Consider prioritization schemes for different message types during high-load scenarios
- Monitor per-connection memory usage, especially when handling large message fragments
- Implement circuit-breakers that degrade service gracefully under extreme load
Frame Size and Message Fragmentation
Large messages create special challenges with Web Sockets. Web Sockets typically handle a smaller message frame size (e.g. 32kb), which means larger messages are broken up into smaller chunks which need to be reconstituted on the receiving end. You will need to:
- Design protocols that properly handle multi-frame messages, especially during connection instability
- Implement timeout mechanisms for partially received fragmented messages.
- Consider streaming approaches for large data transfers instead of single large messages.
- Test fragmentation edge cases including control frames interleaved with fragmented messages.
Standardized Keep-Alive and Health Monitoring
Since Web Sockets are a bi-directional communication channel, both client and server are responsible for detecting the connection stability and health. Your client and server applications will need to consider some or all of the following:
- Establish consistent Ping/Pong usage patterns across your system with clear timing parameters.
- Implement application-level heartbeats separate from WebSocket protocol mechanisms.
- Design escalating health check procedures that can distinguish between different failure modes.
- Consider how firewalls and proxies may affect long-lived connections with timeout policies.
Request-Response Correlation
Web Sockets provide a message stream with no built-in request-response syntax. These are left to the underlying sub-protocol to design for and consider. In order to ensure your protocol and messaging design is robust you should consider:
- Implement message correlation IDs to match responses with their originating requests.
- Design timeout and retry mechanisms for requests that don't receive timely responses.
- Consider how concurrent operations will be managed without native request multiplexing.
Security Implications
Long-lived connections introduce unique security concerns which must be considered in your design. Think about some or all of the following:
- Implement periodic re-authentication without disrupting connections - tokens expire and you need to refresh them while keeping the connection alive.
- Consider rate limiting to prevent DoS attacks - both connection attempts and message frequency need monitoring.
- Define clear message validation rules in your sub-protocol - validate all incoming messages before processing them.
- Use secure WebSocket connections (wss://) in production to protect data in transit.
- Verify the Origin header to prevent cross-site WebSocket hijacking attempts.
- Implement timeouts for inactive connections to free server resources.
Testing Strategy
Web Sockets require more complex testing approaches due to the challenges already discussed. Think about and consider the following testing strategies to validate your solution:
- Simulate connection failures and recoveries to ensure your designs function as expected, particularly consider the failure scenarios which is where problems and edge cases will occur.
- Test partial message delivery and fragmentation to ensure your application is resilient to network interruptions. Web Socket data occurs in frames which are smaller in size to the overall message - this adds to the testing complexities.
- Verify correct behavior under high message volumes to ensure your sub-protocol design functions correctly.
Protocol Design
The sub-protocol you design will impact on the functioning and reliability of your application. When thinking about the sub-protocol design you need to consider:
- Message acknowledgment mechanisms for critical updates. If you need to guarantee a message delivery - this needs to be a specific design choice in your architecture.
- Define clear message structures with versioning support so that you can support backwards compatibility.
- Consider binary formats (Protocol Buffers, MessagePack) for high-throughput applications.
Designing messaging protocols is not easy, and must be a carefully considered part of your solution design. The sub-protocol should consider many of the elements we have discussed throughout this section, some of them are protocol specific which define the semantics of how the client and server communicate.
Remember Web Sockets don't Pub-Sub!
Web Sockets provide the communication channel, the responsibility for building reliable, scalable systems on top of this communication channel requires significant additional design and development effort. In my opinion success or failure of your application design comes down to the underlying sub-protocol. When implementing Web Sockets as your underlying communication mechanism make sure that you fully consider the impact of HOW your systems will talk - this will determine whether you succeed or fail because Web Sockets don't do pub-sub, your client and server applications do that - Web Sockets is your data pipe between them and everything else you have to build or buy!
Top comments (0)