Socket.IO is an open-source, cross-platform library that provides full-duplex bidirectional communication between a client and a server based on events. It is built on top of the WebSocket protocol providing additional capabilities such as automatic reconnection and fallback to HTTP long polling where WebSockets cannot be used.
Socket.IO allows you to implement a wide variety of applications that depend on message exchange, for example, instant messaging, multi-user collaboration, real-time analytics, file-sharing, and notifications.
Yes, Socket.IO is a good choice for building real-time web applications as it offers many features out of the box that will be useful for developers including:
Room and namespace support, allowing you to group clients into rooms who can all receive broadcast or multicast messages.
Automatic reconnection, meaning you don’t have to worry about clients when they go on or offline.
Binary data support, allowing you to exchange more than just chat messages including images or other media.
Socket.IO is not an API in the traditional sense. It is a library or framework that abstracts away the underlying transport mechanism and provides a set of tools and utilities for building real-time, bidirectional communication between a client and server.
Socket.IO comprises of both a client and server component, each of which expose their own APIs.
Socket.IO can use both TCP and UDP as the underlying transport protocol, but it primarily uses TCP.
TCP (Transmission Control Protocol) is a reliable, connection-oriented protocol that ensures data is delivered in order and without errors.
UDP (User Datagram Protocol), on the other hand, is a connectionless, unreliable protocol that sends data without checking if it was received successfully.
UDP is more lightweight than TCP since only the latter establishes a connection between client and server but can only be used by applications resilient against missed messages.
Whilst Socket.IO is explicitly not a WebSocket implementation, there are several similarities. Both are event-based, meaning you would ‘listen’ for events like connect, disconnect or new_message and both allow you to send structured data like JSON objects.
You can think of Socket.IO as an abstraction layer on top of the underlying transport protocol. As well as the underlying communication layer, the library implements additional features such as automatic reconnection, packet buffering, and message acknowledgment as well as falling back to HTTP long-polling if WebSockets are unavailable, adding robustness.
Socket.io Server Example:
Socket.io Client Example:
The library supports two transportation methods: HTTP long-polling and WebSockets. The HTTP long-poll connection is established first and then upgraded to a WebSocket connection if possible. WebSockets cannot run everywhere, for example, they are blocked by many corporate proxies and firewalls, therefore the HTTP long-poll is initiated first since it is more likely to succeed. After the HTTP long-poll connection is established, it is ‘upgraded’ to a WebSocket connection in a process that is entirely transparent to the end user.
Socket.IO consists of two distinct layers, present on both the client and server:
The low-level plumbing is provided by a separate library called Engine.IO
The high-level API which is provided by Socket.IO
As a developer or user, you would not typically interface directly with Engine.IO but this is running behind the scenes to establish the connection, negotiate a transport mechanism and detect any disconnects. When comparing Engine.IO with WebSockets the two are functionally very similar, only Engine.IO provides an abstraction layer allowing you to migrate from a HTTP long-polling connection without (crucially) losing any messages.
The high-level Socket.IO API adds some noteworthy features on top of the basic connectivity provided by Engine.IO:
Buffered events allow you to send events when not connected that will be delivered when the client reconnects. This can lead to spikes in traffic if the client takes a long time to reconnect so you need to code your client accordingly.
Acknowledgments allow you to specify a callback which will be invoked when the other side acknowledges the message has been received.
Broadcasting and multicasting (a concept Socket.IO refers to as Rooms) allow a server to send a message to multiple clients, though a client can't broadcast to other clients.
As with any solution that involves listening for and sending messages the biggest challenge is how to scale beyond a few thousand users.
Socket.IO is a library, it is NOT an infrastructure. As a solution architect or developer, you are responsible for deciding how your solution will reliably scale which is going to involve using multiple server nodes and load-balancing client connections between them. Load balancing comes with its own set of challenges but since Socket.io has been around for over a decade the community has come up with a robust set of best practices, for example, the concept of Adapters allows you to send a broadcast message between clients connected to different servers using a Pub/Sub mechanism.
Still, even though solutions do exist to scale Socket.IO, a lot of consideration is required by your development team and it is very difficult to consider every edge case. In contrast, PubNub provides a highly-scalable, low-latency messaging solution for teams looking to reach production quickly.
Suggested architecture for broadcasting messages across server instances with Socket.IO: