i have a problem over implementing sockets. Case:
the user has n number of rooms in his list,
user should be able to receive notifications from each of the rooms.
method 1) open a socket for each room user has. in this user has to open multiple sockets for each room
method 2) users opens a single socket with room name = userid,
node maintains a list ('room_user') of each room and users in that room (this can be done on connection).
eg
room_user:{
room1 : {
user1Id, user2Id
}
room2 : {
user1Id, user3Id
}
}
For sending a message the server gets the userid's from the list for a specified room and then emits the message in a loop to all users. In this approach the user has to open only one socket but the server has to emit the same message in a loop
i want to know which method would be better suited
If you consider the underlaying TCP/IP broadcast system, you would probably find that it is better that the user have a single websocket connection and the server loop and send the same message again and again (method 2 in your question).
Allow me to explain:
TCP/IP doesn't support broadcasting. For this reason, sending the same message to multiple connections is actually implemented by looping over the list of connections and sending the same message again and again...
It's true that your code will be moving the loop to a higher level of the application, but it would probably be better than having many connections that would hinder your ability to scale the application.
Related
I assigned myself with the task of implementing the chat app (1:1) for my curriculum.Among the various options I used SSE for real time chats.From the example projects I am able to implement the non persistent chat between two clients.In every examples they uses js object and array to store the res object and by iterating them they sent events to particular user.But when implementing the real time chat app the users may increase dramatically So it is not good to exhaust server resources.
I found the some of the other ways to achieve same
functionality but not sure about the performance
SSE+setInterval
I used redis Queue to push offline messages to the user.
when the user establishes the connection push all the unread chats to client.
This process happens immediately when client establishes connection with server.
I faced some problem here, as I have no way of triggering the messages in real time(when both users online).
So I used setInterval with time interval of 1 second for real time communication and write a callback function to check if the Queue is empty else pop message from Queue and sent to user as an event.
Will the above solutions affect performance ? Because I am calling the function for each connected user x 1 second interval.
Long polling
In long polling how can I find if there is new message for user and complete the request ?
Still here setInterval should be used in server side but what about performance?
Websockets
In websockets we have an unique id to find the client in the pool of clients, so we can forward message to particular user when event occurs.
Still websockets uses some ping pong mechanism to make connection persistent but resource utilization is very small as they are network calls with comparatively small data and handled asynchronously so no wastage in server resource.
Questions
How to trigger res.write only when the new message arrives to particular user?
Does SSE+setInterval or longpolling+setInterval degrades performance when user increases?
Else is there any design pattern to achieve this functionality?
Simply use websocket.
It's fast, convinient and simple.
To send message in realtime when both users are logged, find second user by id in users Array or Map and send received message to his websocket.
If you have buffered messages for disconnected user (in memory/database/redis) check it when user connects and send if it exists.
I am designing a system with Socket.io, Nodejs, Expressjs, Redis, Angularjs in which message delivery is very crucial.
Use Case:
My system needs to listen for notifications on resources which can also be shared among multiple users. Sockets are connected to the server with information about resource so that I can maintain a list of sockets for each resource. When there is a notification for that resource I send notification on every socket for that resource.
ResourceID1 = ["scoketID1", "socketID2"] // Two sockets listening to ResourceID1
I update this list on socket disconnect also by removing that specific socket id out or resourceID list.
This way I make sure notification is sent to every user which is sharing the resource and every session of that user along with every socket which can be multiple tabs for one session. In short "Every Socket".
I am also maintaining a hash for the resource notification so that every time there is a new notification for a resource the particular resource notification hash will be updated.
ResourceID1-notificationHash : { key1:"124", key2: "abc" }
The reason for doing this is that if the socket disconnected like user closed the tab or more importantly user Internet disconnected for some reason. and the server does not receive heart beat socket connection is made again and the last message for that resource is sent to that socket.
To make sure that particular socket(client) always receive the message is my implementation enough?
I know I can implement callbacks for an event but what I did is when a particular tab(socket)that was disconnected, is connected again I send the last message for that resource.
Are there any other network glitches which can cause problems for reliable message delivery?
My implementation is different in a sense that for message delivery I am not considering Users, I am considering sockets which can be multiple for just one user like one user can have multiple sessions at the same time lets say in firefox and chrome and then for each session he can have multiple tabs opened. Reason for choosing sockets is my resources can be shared among multiple users so that for one resource update I may have to send the message to multiple users each having multiple sessions and each session having multiple sockets.
I have a use case of socket.io where, within an individual namespace, a client can connect to several rooms. A user needs to authenticate on a per-room basis (because they may not be allowed to access those data streams).
Obviously I can check the authorisation on connection to the namespace using a middleware function and some auth data, but unless those rooms are already in socket.rooms when the connection is initiated, I do not know how to check, when a socket joins a room, whether or not it is authorised and subsequently force it to leave the room if it is not authorised.
Is there a join event or equivalent way of doing this? Like the connection event for a namespace but for a room.
EDIT
Having read through the source for socket.io, it appears that no events are triggered when a socket joins a room, but I might have misunderstood something: on reading the source of socket.io-client, joining rooms isn't inherent in the system, suggesting that this is only something that can be triggered on the server side. In that case, I'm assuming I have to manage the client's joining of rooms myself? If this is true, then I can just have something like:
socket.on('join', function(data) { ... });
so that when a socket wants to listen to a particular data stream, it just emits a "join" event, with some data on which room it wants to join, and I handle the whole thing on the server?
Joining a room can only be done on the server. The client typically sends an application-specific message to the server that indicates to your app that they want to join a specific room and then the server carries out that operation on the user's behalf if the request is valid.
So, all you have to do is route all your code on the server that could join a room through one particular function that can do whatever authentication you want to do. For example, you could simply create a function that was the only way your server code would ever put a socket into a room:
function joinAuth(socket, room) {
// can do anything you want here before actually joining the room
}
I am trying to integrate real time notifications with Node and socket.io in a Symfony Application. I have read a lot of information about this topic and have a working Node application.
nodeClient.js
var socket = io.connect( 'http://192.168.15.106:8080' );
$('a.sendSmile').click(function(){
socket.emit( 'message', { name: 'something' } );
});
socket.on('message', function(data){
console.log(data.name);
});
The problem now is with the above which is working perfectly I am able to send real time notification to all the users at once. But what's the best way to target a single user?
For example a user can send a smile to another user so only the second user should receive the notification and not all the users.
Should I make multiple listeners for node? or any other method to do this?
You need some way of identifying which socket that connected to your server is the one you want to send data to and then you can send to just that socket. You can keep track of user names when users connect or if you have some auth system, you can keep track of which socket belongs to which authenticated user.
Your server holds a list of connected sockets. Each connected one at a time and triggered a connection event on your server when they connected. Your application needs to create a way of knowing which of those connected sockets you want to send the data to. This is not something you've described anything about how you want that to work so we can't really help more specifically.
You can dispatch a notification to single user if you can discriminate that user. For example you can get a user_id on client connection to your nodejs server (the user_id is send from client, inside message) and save it in a key-value store (like Redis, memcache, ...). In this way you can correctly dispatch the notification, arrived from the server (like Symfony2 application), to right user.
I suggest you use Redis, both as a key-value store and for its implementation pattern of the publish/subscribe usable as a channel of communication between the server and the application of realtime.
I have the following code to allow users to join a room to start chatting.
server.on('connect', function(data) {
nickname = prompt('What is your name?');
server.emit('join', {name : nickname, room : $('#roomid').val()});
$('#events').append('<li>Welcome, ' + nickname + '!</li>');
});
However, one concern I had is: what's preventing users from emitting 'join' with hundreds of usernames, spamming the chat room? I'm brand new to real-time programming, so I'm wondering what sort of techniques I can use to preventing this sort of behavior.
There's not really anything from stopping a user from doing this by default. You'll want to build in server-side security to handle this kind of thing; a good example is IRC, where some servers have systems set up which limits or disconnects users who get too spammy. Consider these options for additional logic on the server side:
Limit a user (i.e. make it where the events they send are ignored) if they emit more than a certain number of events in a period of time; disconnect/blacklist them if they do it often or particularly excessively.
Ignore events that are emitted in an unallowed state; for example, keep track of the connected socket's username somewhere (i.e. using socket.set), and if they send another join event, discard it.