Detailed Explanation of SOCKET.IO

For this article you should be familiar with the term socket. In very general term i would say it’s a way of bidirectional communication. Using http protocol you can send a request to server and server can respond on the same request but server can not send any data to client without a client request.Using socket client and server both can send messages to each other. Sockets are used in applications which needs instant messaging like chat application etc.

socket.io provide a simplistic way to interact with sockets. socket.io runs with node.js on server side. Please make sure you have node.js installed on your machine.

Now for example purposes i am creating a node server which would be listening on port 80. There are two files, one is index.js which runs through node.js and other one is index.html which runs on client browser.For running the examples given in this blog, do the following steps:

1.Create a directory by any name.

2.Make that directory your working directory.(cd directory_path)

3.Put index.js and index.html into it.

4.Install socket.io using npm install socket.io.

5.To run the code use node index.js.

6.Access http://localhost in browser.

7.Check server logs on terminal console and client logs through console of browser.

Simple Workflow

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//creating a http server
var app = require('http').createServer(handler)


//io is Server class object 
var io = require('socket.io')(app);

var fs = require('fs');

//making server listen to port 80
app.listen(80);

//using this function it serves index.html on localhost/index.html
function handler (req, res) {
  fs.readFile(__dirname + '/index.html',
  function (err, data) {
    if (err) {
      res.writeHead(500);
      return res.end('Error loading index.html');
    }

    res.writeHead(200);
    res.end(data);
  });
}


//this gets called when a socket is created on client request
io.on('connection', function (socket) {
    console.log("connection established");
    socket.emit('a message','hello from server');
    socket.on('reply',function(msg){
      console.log(msg);
    });
  });

//you can write io.sockets.on('connection',.....) too because 'on' is a Namespace class 
//function.When you write io.on(...) it calls io.sockets.on(..) internally where 
//io.sockets = this.of('/') which is default Namespace.In the Namespace section i will be
//covering this in detail.

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script src="/socket.io/socket.io.js"></script>
<script>
//socket.io.js exposes a variable io


var socket = io('http://localhost');
//io.connect(...) & io(...) both are the same thing.
//Both points to the same function and return socket.

//on getting 'a message' event through socket from server
socket.on('a message', function (msg) {
	console.log(msg);
	socket.emit('reply','hello from client');
});

</script>

What happens here is client tries to establish a socket connection with server. On socket creation socket emit a event ‘a message’ which is later received by client.After receiving this event client triggers another event ‘reply’ which is later received by server.

When this code is run:

server logs:

connection established
hello from client

client logs:

hello from server

Diagram Class Diagram

Namespaces

In actual sockets there is no concept of namespaces. socket.io introduced this concept to provide a highlevel seperation layer between sockets. A socket can be a part of one namespace only.By default all the sockets connect to default namespace (‘/’) if you don’t provide a custom namespace.

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//creating a custom Namespace object, by default it is io.of('/')
var chat = io.of('/chat');
chat.on('connection', function (socket) {
    console.log("socket inside chat namespace created");
    //sending message to this socket only
    socket.emit('a message', "message sent from chat namespace");
    //sending message to all the sockets present in chat namespace
    chat.emit('a message', "message sent for all the sockets for chat namespace");

    //sending message to all the sockets present in default namespace
    //io.emit(...) calls io.sockets.emit(...) 
    io.emit('a message', "message sent from default namespace");

    socket.on('reply',function(msg){
      console.log(msg);
    });
  });

index.html

1
2
3
4
5
var chat_socket = io('http://localhost/chat');
chat_socket.on('a message', function (msg) {
     console.log(msg);
     chat_socket.emit('reply','message received at client');
});

Here client is trying to create socket connection with a custom namespace (‘/chat’) . After creating the socket in this namespace it triggers the ‘connection’ event on server.Then server is emiting a message first for the created socket and then for all the sockets present in that namespace. Later it tries to emit a message to default namespace but as no socket is present for default namespace,nothing happened.

server logs:
socket inside chat namespace created
message received at client
message received at client

client logs:
message sent from chat namespace
message sent for all the sockets for chat namespace

Diagram Architecture Diagram

Rooms

In a namespace you can create rooms. A socket can be the part of multiple rooms.Each socket in socket.io is identified by a random, unguessable, unique identifier Socket#id. For your convenience, each socket automatically joins a room identified by this id.Socket can join a room only through server. Client can send a message to server saying which room it should join and server can process the request accordingly.

index.js

1
2
3
4
5
6
7
8
9
10
11
12
io.on('connection', function (socket) {
    console.log("connection established");
    socket.emit('a message','hello from server');
    //I named the event join_room, you can name it according to your choice
    socket.on('join_room',function(msg){
      //In this msg information regarding room is present which has been sent by client
      socket.join(msg.room); //msg.room = room1
      //sending message to all the sockets present in room1
      io.to("room1").emit("msg_for_room1","mesage for room1");
    });

  });

index.html

1
2
3
4
5
6
7
8
9
10
//normal event for socket
socket.on('a message', function (msg) {
     console.log(msg);
     socket.emit('join_room',{room: 'room1'});
  });

//event for sockets connected with room1
socket.on('msg_for_room1', function (msg) {
     console.log(msg);
  });

A socket can join the room using join function of Socket class. And server can send event to all sockets present in the room using io.to(room_name).emit(…).

server logs:
connection established

client logs:
hello from server
mesage for room1


For sending event to all clients except sender use:

    
socket.broadcast.emit('message', "sending message to all clients except sender");

For sending to all clients present in a room except sender use:

 
socket.broadcast.to('room').emit('message', 'sending to all clients present in a room except sender');
comments powered by Disqus