Namespaces and rooms short overview
Socket.io has namespaces and rooms. This is a special mechanism that allows separating users by different independent groups.
Difference between namespaces and rooms and my assumption why it is used for
In socket.io difference between is in implementations how it is used. I don’t see big differences in solving our problems, They are both do the same thing creating groups. Next what I want to say it’s that for me much easier to use namespaces than rooms. Each namespace has his own server object, For creating namespace we create a new instance of socket.io server
1 2 3 4 5 |
var nsp = io.of('/hello-smy-namespace'); nsp.on('connection', function(socket){ console.log('someone connected'); socket.emit('message', 'everyone!'); }); |
for creating rooms we listening event from a client and then join a client to a room.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
socket.on( 'room', function(msg) { console.log( msg ); if( msg == 'main' ) { socket.join( 'main', function(){ console.log('user is connected to main'); io.to( 'main' ).emit( 'massage', 'Here we are main' ); socket.broadcast.to( 'main' ).emit( 'massage', 'Here we are main [broadcast]' ); // socket.broadcast.to( 'room', 'a new user has joined the room'); } ); }else if ( msg == 'room1' ) { socket.join( 'room1', function(){ console.log('user is connected to room1'); io.to( 'room1' ).emit( 'massage', 'Here we are room1' ); // io.to( 'room1' ).broadcast.emit( 'massage', 'Here we are room1' ); } ); }else if ( msg == 'room2' ) { socket.join( 'room2', function(){ console.log('user is connected to room2'); io.to( 'room2' ).emit( 'massage', 'Here we are room2' ); // io.to( 'room2' ).broadcast.emit( 'massage', 'Here we are room2' ); } ); } }); |
for rooms, we have to pass from clients JSON object with room and message. We can’t simply pass data using io.emit without passing JSON because our server can only do emit to some rooms. Clients can only send messages by using some event without specifying rooms. Remember this is the main feature. It leads us to send all our message using JSON object with a room as a necessary parameter. Example of JSON possible data { room: room1, message: “Hello world” }.
In general namespaces, we use for creating a different context something like a real-time chat and comment system or game, that we could put on the same pages or different. Rooms we use for grouping users in the same contexts, something like for chat separate users to many chats or for game separating users to play in two instances of the same game. This is how it uses. if you have a chat use room for separating. if you have chat and comment system use namespaces. And this si up to you. Not exists strict rules.
Overview code example with rooms
file 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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
const express = require( 'express' ); const http = require( 'http' ); const socket_io = require( 'socket.io' ); const path = require( 'path' ); var exphbs = require( 'express-handlebars' ); // initialization variables var app = express(); // create a server var server = http.Server(app); var io = socket_io(server); app.use( express.static( path.join( __dirname + "/public" ) ) ); // set up template engine app.engine( '.hbs', exphbs( { extname: '.hbs', defaultLayout: 'main', partialsDir: [ 'views/partials/' ], helpers: { eq: function( v1, v2 ) { return v1 === v2; } } } ) ); app.set( 'view engine', '.hbs' ); // routers app.get( '/', function( req, res) { res.render( 'index', { layout: 'main', room: 'main', } ); } ); app.get( '/room1', function( req, res ) { res.render( 'index', { layout: 'main', room: 'room1', } ); } ); app.get( '/room2', function( req, res ) { res.render( 'index', { layout: 'main', room: 'room2', } ); } ); app.get( '/room3', function( req, res ) { res.render( 'index', { layout: 'main', room: 'room2', namespace: 'room2', } ); }) // creating a server server.listen( 3000, function() { console.log('Listening port 3000...'); } ); // rooms // main function io.on( 'connect', function(socket) { console.log('a user connected'); // room joiner socket.on( 'room', function( msg ) { msg = JSON.parse( msg ); var room = msg.name; console.log(room); console.log( msg ); if( room == 'main' ) { socket.join( 'main', function(){ console.log('user is connected to main'); // we can emit message using io object, this is our server io.to( 'main' ).emit( 'message', 'Here we are main' ); // we can only broadcast using socket socket.broadcast.to( 'main' ).emit( 'message', 'Here we are main [broadcast]' ); } ); }else if ( room == 'room1' ) { socket.join( 'room1', function(){ console.log('user is connected to room1'); // we can emit message using io object, this is our server io.to( 'room1' ).emit( 'message', 'Here we are room1' ); // we can only broadcast using socket socket.broadcast.to( 'room1' ).emit( 'message', 'Here we are room1 [broadcast]' ); } ); }else if ( room == 'room2' ) { socket.join( 'room2', function(){ console.log('user is connected to room2'); // we can emit message using io object, this is our server io.to( 'room2' ).emit( 'message', 'Here we are room2' ); // we can only broadcast using socket socket.broadcast.to( 'room2' ).emit( 'message', 'Here we are room2 [broadcast]' ); } ); } }); socket.on( 'message', function( msg ) { console.log( msg ); } ); // socket.join( 'room1' ); // io.to('room1').emit('some event'); } ); |
handlebars template file /views/layouts/main.hbs
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 41 42 43 44 45 |
<!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title></title> </head> <body> {{{body}}} <input type="text" name="message" value=""> <button type="button" name="button">Send message</button> <script src="/jquery.js" charset="utf-8"></script> <script src="/socket.io/socket.io.js"></script> <script type="text/javascript"> var io = io(); jQuery(document).ready(function($) { // var io = io( '/room3' ); // create a JSON object var message = { name: "{{room}}", message: "This ir room: {{room}}", } // client wants to join a room1 io.emit( 'room', JSON.stringify(message) ); io.on( 'room', function(msg) { console.log(msg); }); io.on( 'message', function(msg) { console.log(msg); }); io.emit( 'message', 'hello world' ); // $('input[name=message]').click(function(event) { // io.to( '{{room}}' ); // }); }); </script> </body> </html> |
In code, we can see we can to broadcast using a socket and to emit using a server. We create one object io that is our socket.io server and nothing else. Let’s overview example with namespaces. It looks more straightforward.
Code example with namespaces
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
const express = require( 'express' ); const http = require( 'http' ); const socket_io = require( 'socket.io' ); const path = require( 'path' ); var exphbs = require( 'express-handlebars' ); // initialization variables var app = express(); // create a server var server = http.Server(app); var io = socket_io(server); app.use( express.static( path.join( __dirname + "/public" ) ) ); // set up template engine app.engine( '.hbs', exphbs( { extname: '.hbs', defaultLayout: 'main', partialsDir: [ 'views/partials/' ], helpers: { eq: function( v1, v2 ) { return v1 === v2; } } } ) ); app.set( 'view engine', '.hbs' ); // routers app.get( '/', function( req, res) { res.render( 'index', { layout: 'main', namespace: 'main', } ); } ); app.get( '/room1', function( req, res ) { res.render( 'index', { layout: 'main', namespace: 'room1', } ); } ); app.get( '/room2', function( req, res ) { res.render( 'index', { layout: 'main', namespace: 'room2', } ); } ); app.get( '/room3', function( req, res ) { res.render( 'index', { layout: 'main', namespace: 'room3', } ); }) // creating a server server.listen( 3000, function() { console.log('Listening port 3000...'); } ); // custome namespace var nsp = io.of('/main'); nsp.on('connection', function(socket){ console.log('someone connected to /main'); this.emit( 'message', 'Here we are /main !' ); io.emit( 'message', 'for everybody /main !' ); // socket.broadcast.emit( 'message', 'broadcast /main !' ); }); var nsp1 = io.of('/room1'); nsp1.on('connection', function(socket){ console.log('someone connected to /room1'); socket.emit('message', 'Here we are /room1 !'); io.emit( 'message', 'for everybody /main !' ); }); var nsp2 = io.of('/room2'); nsp2.on('connection', function(socket){ console.log('someone connected to /room2'); socket.emit('message', 'Here we are /room2 !'); }); var nsp3 = io.of('/room3'); nsp3.on('connection', function(socket){ console.log('someone connected to /room3'); socket.emit('message', 'Here we are /room3 !'); }); |
main.hbs
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 |
<!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title></title> </head> <body> {{{body}}} <input type="text" name="message" value=""> <button type="button" name="button">Send message</button> <script src="/jquery.js" charset="utf-8"></script> <script src="/socket.io/socket.io.js"></script> <script type="text/javascript"> var io = io("http://localhost:3000/{{namespace}}"); jQuery(document).ready(function($) { // var io = io( '/room3' ); io.on( 'message', function(msg) { console.log(msg); }); io.emit( 'message', 'hello world' ); // $('input[name=message]').click(function(event) { // io.to( '{{room}}' ); // }); }); </script> </body> </html> |
Cases How we have to use namespaces and rooms in socket.io
Conclusions