top of page

Differences between WebSockets and Socket.IO



WebSockets and Socket.IO are probably two of the most popular solutions for implementing real-time communications in the modern web. But how do they differ?


When building a real-time application, there’s a moment where you have to choose how to implement the real-time data exchange between client and server. WebSockets and Socket.IO are probably two of the most popular solutions for implementing real-time communications in the modern web. But which one should we choose? What are the differences between these two technologies? Let’s find out!

WebSockets

When talking about WebSockets, we refer to a web communication protocol that provides a full-duplex communication channel over a single TCP connection. In few words, it allows interactions between client and server with minimum overhead, allowing us to build applications that use the advantages of real-time communications.

For instance, imagine if you’re building a chat app: you need to receive and send data as soon as possible, right? Well, that’s the right job for WebSockets! You can open one TCP connection and share data leaving it open as long as you need it.

WebSockets first appeared in 2010 in Google Chrome 4, and the first RFC (RFC 6455) has been published one year later, in 2011.

Great use cases for WebSockets includes:

  • Chat Applications

  • Multiplayer Games

  • Collaborative Editing

  • Social Feeds

  • Location-based Applications

and many more.

Socket.IO

Socket.IO is a JavaScript library built on top of WebSocket… and other technologies. In fact, it uses WebSockets when available, but it’s ready to fall back to other technologies such as Flash Socket, AJAX Long Polling, AJAX Multipart Stream, and many more; that allows Socket.IO to be used in contexts where WebSockets are not supported. There’s an amazing article in the Ably blog which describes its features in depths.

Differences between WebSocket and Socket.IO

The main advantages of Socket.IO over WebSockets are:

  • Unlike WebSocket, Socket.IO allows you to broadcast a message to all the connected clients. For instance, if you’re writing a chat application and you want to notify all the connected clients that a new user has joined the chat, you can easily broadcast that message in one shot to everyone. Using plain WebSocket, you’ll need a list of all the connected clients and then send the message directly one by one.

  • Proxies and load balancers make WebSockets hard to implement and scale. Socket.IO supports these technologies out of the box.

  • As said before, Socket.IO can fall back to technologies other than WebSockets when the client doesn’t support it.

  • If (for some reason) a WebSocket connection drops, it will not automatically reconnect… but guess what? Socket.IO handles that for you!

  • Socket.IO APIs are built to be easier to work with.

So, it seems that Socket.IO is something like “the heaven of real-time communications,” right? Well, there are actually some good reasons for using vanilla WebSockets.

First of all, every modern browser supports WebSockets these days. Socket.IO uses much more boilerplate code and resources to make it fall back to other technologies. Most of the time, you don’t need this level of support. Even in terms of network traffic, Socket.IO is way more expensive. In fact, with plain WebSockets, the browser may need to run just two requests:

  • The GET request for the HTML page

  • The UPGRADE connection to WebSocket


and that’s it. You’re ready to start real-time communication with your server! But what about Socket.IO?

  • The GET request of the HTML page

  • Socket.IO client library (207kb)

  • Three long polling Ajax request

  • The UPGRADE connection to WebSocket

in a world where we’re using many JavaScript code and libraries are drastically reducing their weight… 207kb is a lot! And what about all these requests? What a waste of network traffic!

There’s even an npm package called websocket-vs-socket.io that has been built for comparing the network traffic of those two technologies:

WebSocket network traffic:

Socket.IO network traffic:


what a huge difference!

Writing realtime code

So far, we have just seen some differences on paper, but how do they differ when writing a real-time application?

Simple WebSocket server In the following Node.js program, we’re creating a WebSocket server exposed on port 3001. Every time that a client connects, we’ll assign a unique ID to its session. When the client sends a message, we’ll reply with the following format: [<client-id>]: <message>So he’ll know that the message has been successfully sent.

const WebSocket = require("ws");
const UUID = require("uuid");
const wss = new WebSocket.Server({port: 3000});

wss.on("connection",ws=>{
    ws.id=UUID();
    
    ws.on("message",message=>{
        ws.send(`[${ws.id}]: ${message}`);
    });
});

Great! But what if I want to broadcast that message to every connected client? WebSockets doesn’t support message broadcasting by default! That’s right, but message broadcasting is still easy to implement with vanilla WebSockets:

const WebSocket = require("ws");
const UUID = require("uuid");
const wss = new WebSocket.Server({port: 3000});

function broadcast(clientId,message){
    wss.clients.forEach(client=>
    {
        if(client.readyState === WebSocket.OPEN){
            client.send(`[${clientId}]: ${message}`);
        }
     });
 }
 
 wss.on("connection",ws=>{
   ws.id=UUID();
   ws.on("message",message=>broadcast(ws.id,message));
 });

So easy! As you can see, the WebSocket.Server keeps track of every connected client, so we can loop over them and send the desired message to everyone! We’ve just implemented the easiest chat server ever! You can test the code above with any WebSocket client, both on desktop or via Chrome Extension.

Simple Socket.IO server Ok, that has been incredibly easy! But Socket.IO promises to make it even easier! How should we implement the same server with that library?

const io = require("socket.io");
const server = io.listen(3002);

server.on("connection",socket=>{
    
    socket.on("message",message=>{
        socket.emit(`[${socket.id}]: ${message}`);
        socket.broadcast.emit(`[${socket.id}]: ${message}`);
     });
 });

Wow! Nearly half of the WebSocket server code! As you can see, with the Socket.IO native broadcast method, we’re not sending the message back to the sender; for that reason, we’ll need to emit that message to the client manually.

But there’s a problem: you can’t test it on a standard WebSocket client (as we’ve seen in the previous example). That’s because (as said before), Socket.IO doesn’t use plain WebSockets, but mixes multiple technologies to support as many clients as possible (and to avoid certain problems, as described above). So how do can you test it?

<html>
    <head>
        <scriptsrc="https://cdn.jsdelivr.net/npm/socket.io-client@2.3.0/dist/socket.io.slim.js">
        </script>
     </head>
     <body>
         <scripttype="text/javascript">
             ioClient=io.connect("http://localhost:3000");
             ioClient.on("connect",socket=>{
                 ioClient.send("Hello everybody!");
                 ioClient.on("message",msg=>console.log(msg));
            });
         </script>
      </body>
</html>

You’ll need to use the Socket.IO client. In the above example, we’re using a CDN-delivered client that will allow us to make some quick and dirty tests on a web browser.

As you can see, these two examples may not seem so different… but when it comes to compatibility, you have to keep in mind that Socket.IO will always work with its own client library, so you won’t be able to use it for purposes other than web development. That is not true for WebSockets, that might be used to solve a large set of problem, such as p2p communications, real-time server-to-server data transfer and so on.

Things to keep in mind

As we’ve seen at the beginning, there are many problems that Socket.IO tries to solve.

  • Horizontal scaling. Let’s say that your chat app is having a lot of success, and you need to add another server and a load balancer to handle all the requests. Well, if you’re opening a connection on the “server 1", but then the load balancer switches you to the “server 2", you’ll get the following error: "Error during WebSocket handshake: Unexpected response code: 400". Socket.IO solves that problem using a cookie (or routing the connection based on their originating address), but WebSockets doesn’t provide an alternative mechanism out of the box.

  • Performances. As we’ve said before, Socket.IO provides multiple layers of abstraction over the vanilla WebSockets transport layer. It will also enforce JSON packaging to send real binary data from client to server (and vice versa). If you ever need to achieve that level of performance, you’ll need to customize the library to avoid that specific behavior. With vanilla WebSockets, you will never have this problem. So, what should I choose?

Well, there’s not a simple answer to this question. Socket.IO may make things a bit easier for sure; you don’t have to worry about load balancer-related issues, connection failures, and message broadcasting… but are you sure you really need these features? Just the Socket.IO client library alone is heavier than React, Redux and React-Redux packaged together. Are you sure that you can’t use the browser native WebSocket API?

Another thing to keep in mind is that Socket.IO, implemented server-side, is a custom library/framework where most of the time, you’re not following the vanilla WebSocket logic because of the abstractions applied by Socket.IO itself. If you’re refactoring your Node.js microservices (let’s say) to Go, Elixir, Java, or any other language, you’ll have to rewrite most of the logic behind the Socket.IO behavior to achieve the same results with vanilla WebSockets. For instance, think about broadcasting a message to every connected client: with Socket.IO is just one method (.broadcast) but in vanilla WebSockets, you’ll have to implement it on your own, so you’ll have to rethink the way it works. So maybe, it is worth it to start to work with vanilla WebSockets from the beginning, so it will be easier to refactor, extend or implement new features in other languages (if you’re writing microservices/lambdas, etc.).



Source: Medium


The Tech Platform

0 comments

Recent Posts

See All
bottom of page