top of page
Writer's pictureTandid Alam

Socket.IO for Beginners

Updated: Nov 5, 2022

- Introduction

- Initial Setup

- Installation

- Server Initialization

- Client Initialization

- Emitting Events

- Listening to Events

- Broadcasting

- Rooms

- Cheatsheet

- Code Example


 

Introduction


Socket.IO is a library that enables low-latency, bidirectional and event-based communication between a client and a server.


It is built on top of the WebSocket protocol and provides additional guarantees like fallback to HTTP long-polling or automatic reconnection.


Although Socket.IO indeed uses WebSocket for transport when possible, it adds additional metadata to each packet. That is why a WebSocket client will not be able to successfully connect to a Socket.IO server, and a Socket.IO client will not be able to connect to a plain WebSocket server either.


Socket.IO is composed of two parts:

  • A server that integrates with (or mounts on) the Node.JS HTTP Server socket.io

  • A client library that loads on the browser side socket.io-client


 

Initial Setup


Installation


You will need to install socket for both the server and the client.


To install for the server:

npm install socket.io

To install for the client:

npm install socket.io-client

Server Initialization


For your server side, you have to set up your node/express server first.

const io = require("socket.io")();
// or
const { Server } = require("socket.io");
const io = new Server();

The server instance emits one event which is the connection string. The first argument is the socket instance.


io.on("connection", (socket) => {
    console.log(socket.id); // ojIckSD2jqNzOqIrAGzL
});


Client Intialization


To get the io object for the client you can do either of the following:


Add script to html:

  <script src="/socket.io/socket.io.js"></script>

Import:

// ES6 import or TypeScript
import { io } from "socket.io-client";

// CommonJS
const io = require("socket.io-client");

Initialize the connection:

const socket = io.connect("http://localhost:3001"); 
//Pass in the URL of your server

If the frontend is served differently from the domain of your server, you might have to use CORs on the server.


 

Emitting Events


The Socket.IO API is inspired from the Node.js EventEmitter, which means you can emit events on one side and register listeners on the other:


To emit events you use emit() where you pass in the name of the event and an argument:

// server-side
io.on("connection", (socket) => {
    socket.emit("hello", "world");
});
  
// client-side
socket.on("hello", (arg) => {
    console.log(arg); // world
});

What's happening here? Once a connection is made, the socket emits an event called "hello", which contains the string "world" as an argument. The client listens for the event "hello" and in doing so, it logs the value of the arg to the console.


This works the other way around as well:

// server-side
io.on("connection", (socket) => {
  socket.on("hello", (arg) => {
     console.log(arg); // world
  });
});
  
// client-side
socket.emit("hello", "world");

 

Listening to Events


Most of the time, you will be using the on() method to listen to events where you pass in an event name and a listener function at the end.


Here are some other common Event Listeners:


socket.once(eventName, listener) - Adds a one-timelistener function for the event named eventName


socket.once("details", (...args) => {
  // ...
});

socket.off(eventName, listener) - Removes the specified listener from the listener array for the event named eventName.


const listener = (...args) => {
    console.log(args);
}
  
socket.on("details", listener);
  
// and then later...
socket.off("details", listener);

socket.removeAllListeners([eventName]) - Removes all listeners, or those of the specified eventName.


// for a specific event
socket.removeAllListeners("details");
// for all events
socket.removeAllListeners();

Read more about listeners here: Listening to events | Socket.IO


 

Broadcasting


Broadcasting is a server-only feature that emits an event to everyone but the user themselves.


You simply add the broadcast function before your emitter:

io.on("connection", (socket) => {
    socket.broadcast.emit("hello", "world");
});

In certain cases, you may want to only broadcast to clients that are connected to the current server. You can achieve this with the local flag:

io.local.emit("hello", "world");

If you want to broadcast to specific people, you will need to create a room.


 

Rooms


A room is an arbitrary channel that sockets can join and leave. It can be used to broadcast events to a subset of clients:


You can call join to subscribe the socket to a given channel:


io.on("connection", socket => {
    socket.join("some room");
});

And then simply use to or in (they are the same) when broadcasting or emitting:

io.to("some room").emit("some event");

You can emit to several rooms at the same time:

io.to("room1").to("room2").to("room3").emit("some event");

In that case, a union is performed: every socket that is at least in one of the rooms will get the event once (even if the socket is in two or more rooms).


To leave a channel you call leave in the same fashion as join.


 

Cheatsheet


Server Side Cheatsheet


  io.on("connection", (socket) => {

    // basic emit
    socket.emit(/* ... */);
  
    // to all clients in the current namespace except the sender
    socket.broadcast.emit(/* ... */);
  
    // to all clients in room1 except the sender
    socket.to("room1").emit(/* ... */);
  
    // to all clients in room1 and/or room2 except the sender
    socket.to("room1").to("room2").emit(/* ... */);
  
    // to all clients in room1
    io.in("room1").emit(/* ... */);
  
    // to individual socketid (private message)
    io.to(socketId).emit(/* ... */);
  
    // to all clients on this node (when using multiple nodes)
    io.local.emit(/* ... */);
  
    // to all connected clients
    io.emit(/* ... */);
    
  });

Client Side Cheatsheet


// basic emit
socket.emit(/* ... */);

// with acknowledgement
socket.emit("question", (answer) => {
  // ...
});


Reserved EventNames

  • connect

  • connect_error

  • disconnect

  • disconnecting

  • newListener

  • removeListener


 

Code Example


Server Side Code


const express = require("express");
const app = express();
const http = require("http");
const { Server } = require("socket.io");
const cors = require("cors");

app.use(cors());

const server = http.createServer(app);

const io = new Server(server, {
  cors: {
    origin: "http://localhost:3000",
    methods: ["GET", "POST"],
  },
});

io.on("connection", (socket) => {
  console.log(`User Connected: ${socket.id}`);

  socket.on("join_room", (data) => {
    socket.join(data);
  });

  socket.on("send_message", (data) => {
    socket.to(data.room).emit("receive_message", data);
  });
});


React Client Side Code


import "./App.css";
import io from "socket.io-client";
import { useEffect, useState } from "react";

const socket = io.connect("http://localhost:3001");

function App() {
  //Room State
  const [room, setRoom] = useState("");

  // Messages States
  const [message, setMessage] = useState("");
  const [messageReceived, setMessageReceived] = useState("");

  const joinRoom = () => {
    if (room !== "") {
      socket.emit("join_room", room);
    }
  };

  const sendMessage = () => {
    socket.emit("send_message", { message, room });
  };

  useEffect(() => {
    socket.on("receive_message", (data) => {
      setMessageReceived(data.message);
    });
  }, [socket]);
  
  return (
    <div className="App">
      <input
        placeholder="Room Number..."
        onChange={(event) => {
          setRoom(event.target.value);
        }}
      />
      <button onClick={joinRoom}> Join Room</button>
      <input
        placeholder="Message..."
        onChange={(event) => {
          setMessage(event.target.value);
        }}
      />
      <button onClick={sendMessage}> Send Message</button>
      <h1> Message:</h1>
      {messageReceived}
    </div>
  );
}

export default App;


 

Learning Resources





Kommentare


bottom of page