Unable to send private message to target socket id - node.js

I am unable to get two users chatting to each other despite reducing the complexity and the potential code that could have caused the issue.
I am able to emit to all connected sockets so I have established it's not an issue in context of emit/on structure but rather; coming from the way i'm handling the private socket ids.
I have tried various versions of trying to send the private message to the correct socket id; I have tried older ways such as socket.to and the current way from the docs which is io.to(sockid).emit('event' message); all these variations have been unable to help me. I have consoled out the socket id I have on my Angular client side by printing console.log('THIS IS MY SOCKET '+this.socket.id) and comparing it to the value I have in Redis using redis-cli and they both match perfectly every time which doesn't give me too much to go on.
problem arises here:
if (res === 1) {
_active_users.get_client_key(recipient)
.then(socket_id => {
console.log('======='+io.sockets.name)
console.log('I am sending the message to: '+ recipient + 'and my socket id is'+ socket_id)
// socket.to(socket_id)socket.emit('incoming', "this is top secret"
io.of('/chat').to(socket_id).emit('incoming', "this is top secret")
})
.catch(error => {
console.log("COULD NOT RETRIEVE KEY: " + error)
})
Here is the link to the pastebin with more context:
https://pastebin.com/fYPJSnWW
The classes I import are essentially just setters and getters for handling the socket id you can think of them as just a worker class that handles Redis actions.
Expected: To allow two clients to communicate based on just their socket ids.
Actual:
am able to emit to all connected sockets and receive the expected results but the problem arises when trying to send to a specific socket id from a unknown reason.

Issue was coming from my front end.. I hope nobody has a headache like this! but here is what happened; when you're digging your own hole you often don't realise how deep you got yourself if you don't take the time to look around. I had two instances of the sockets. I instantiated both and used the one to connect and the other to send the message; which of course you cannnot do if you want things to work properly. So what I did was created only one instance of the socket in and and passed that ref of the socket around where I needed it which is ( sendMessage(username, socket) getMessage(socket)
ngOnInit(
this.socket = io.connect('localhost:3600',{
reconnection: true,
reconnectionDelay: 1000,
reconnectionDelayMax : 5000,
reconnectionAttempts: Infinity});

Related

Change Socket for another user

I'm trying to develop an API for multiplayer online using socket programming in node js
I have some basic questions:
1. How to know which connection is related to a user?
2. How to create a socket object related to another person?
3. When it's opponent turn, how to make an event?
4. There is a limited time for move, how to handle the time to create an event and change turn?
As it is obvious I don't know how to handle users and for example list online users
If you can suggest some articles or answering these questions would be greate
Thanks
Keep some sort of data structure in memory where you are saving your sockets to. You may want to wrap the node.js socket in your own object which contains an id property. Then you can save these objects into a data structure saved in memory.
class User {
constructor(socket) {
this.socket = socket;
this.id = //some random id or even counter?
}
}
Then save this object in memory when you get a new socket.
const sockets = {}
server = net.createServer((socket) => {
const user = new User(socket);
sockets[user.id] = user
})
I am unsure what you mean by that, but maybe the above point helps out
This depends on when you define a new turn starts. Does the new turn start by something that is triggered by another user? If so use your solution to point 2 to relay that message to the related user and write something back to that socket.
Use a timeout. Maybe give your User class an additional property timeout whenver you want to start a new timeout do timeout = setTimeout(timeouthandler,howlong) If the timeouthandler is triggered the user is out of time, so write to the socket. Don't forget to cancel your timeouts if you need to.
Also, as a side note, if you are doing this with pure node.js tcp sockets you need to come up with some ad-hoc protocol. Here is why:
socket.on("data", (data) => {
//this could be triggered multiple times for a single socket.write() due to the streaming nature of tcp
})
You could do something like
class User {
constructor(socket) {
this.socket = socket;
this.id = //some random id or even counter?
socket.on("data", (data) => {
//on each message you get, find out the type of message
//which could be anything you define. Is it a login?
// End of turn?
// logout?
})
}
}
EDIT: This is not something that scales well. This is just to give you an idea on what can be done. Imagine for some reason you decide to have one node.js server instance running for hundreds of users. All those users socket instances would be stored in the servers memory

How can I simulate latency in Socket.io?

Currently, I'm testing my Node.js, Socket.io server on localhost and on devices connected to my router.
For testing purposes, I would like to simulate a delay in sending messages, so I know what it'll be like for users around the world.
Is there any effective way of doing this?
If it's the messages you send from the server that you want to delay, you can override the .emit() method on each new connection with one that adds a short delay. Here's one way of doing that on the server:
io.on('connection', function(socket) {
console.log("socket connected: ", socket.id);
// override the .emit() method
const emitFn = socket.emit
socket.emit = (...args) => setTimeout(() => {
emitFn.apply(socket, args)
}, 1000)
// rest of your connection handler here
});
Note, there is one caveat with this. If you pass an object or an array as the data for socket.emit(), you will see that this code does not make a copy of that data so the data will not be actually used until the data is sent (1 second from now). So, if the code doing the sending actually modifies that data before it is sent one second from now, that would likely create a problem. This could be fixed by making a copy of the incoming data, but I did not add that complexity here as it would not always be needed since it depends upon how the caller's code works.
An old but still popular question. :)
You can use either "iptables" or "tc" to simulate delays/dropped-packets. See the man page for "iptables" and look for 'statistic'. I suggest you make sure to specify the port or your ssh session will get affected.
Here are some good examples for "tc":
http://www.linuxfoundation.org/collaborate/workgroups/networking/netem

[Node.JS Socket.io]communication between two targeted sockets

I'm currently working on a small node.js game.
Game supposedly has a global chat, with a "logged in" list to challenge people.
For the chat and the logged in list, i'm using the default socket.io room/namespace.
I successfully send the challenge request with following code
// When a user sends a battle challenge
socket.on("sendChallenge", function(data) {
// Try with room
socket.join('battleRoom');
var data= {
"userID": data.targetID,
"challengerName": data.challengerName
};
console.log(data.challengerName + " challenged " + data.userID);
// broadcast the message, but only the concerned player will answer thanks to his ID
socket.broadcast.emit('receiveChallenge', data);
});
Client side, I then have this code :
socket.on('receiveChallenge', function (data) {
if (data.userID == userID) {
alert("received challenge from " + data.challengerName);
socket.emit('ack');
}
});
The right player indeed receive the alert, and sends 'ack' to the server :
socket.on('ack', function() {
socket.join('battleRoom');
socket.to('battleRoom').broadcast.emit('receiveMessage', 'SYSTEM: Battle begun');
//socket.to('battleRoom').emit('receiveMessage', 'SYSTEM: Battle begun');
})
Except that the "socket.to('battleRoom').broadcast.emit('receiveMessage', 'SYSTEM: Battle begun');" is only received by the challenger and not by the challenged, and I'm stuck.
(the 2nd line is commented because challenger received 2 messages and challenged received none)
The way i understand it, on the server, the functions socket.on() have "socket" as the client that sent the message, and then you use broadcast to send to all others.
Why is why, in the sendChallenge event, i have the socket.join('battleRoom') for the challenger to enter battleRoom.
I then broadcast the challenge, and asks the client to acknowledge the challenge.
In the ack, the client then supposedly joins battleRoom too.
But i'm obviously doing something wrong, and i can't seem to see what...
I want both the challenger and the challenged communicating through the server.
A link to an image more or less showing the situation : Here
(screen is during the second time i clicked on the quickFight button, showing the Battle begun of the 1st click on the left, and the alert that user was challenged on the right)
Thanks in advance for your help!
As per the socket.io documentation broadcast does the following:
Broadcasting messages
To broadcast, simply add a broadcast flag to emit and send method calls. Broadcasting means sending a message to everyone else except for the socket that starts it.
So when you do:
socket.to('battleRoom').broadcast.emit('receiveMessage', 'SYSTEM: Battle begun');
You do not emit to the socket that broadcasted to the room. Simply replace that line with the following:
io.to('battleRoom').emit('receiveMessage', 'SYSTEM: Battle begun');
This is assuming that you named your socket.io object io, if you named it differently use that.
Just as a side-note, it's not necessary here to broadcast your original message to everyone if you create an associative array with all your connected socket id's (or sockets themselves). Then you can find the challenged socket id in your array and only emit to them specifically with the challenge. This would cut down on your server calls.

how to handle concurrency issues in nodejs

I was preparing a chat application on nodejs using socket-io
The problem is with concurrent callbacks, explaination is as follows:
I keep in database socketId of related users,
On disconnect event of socket-io I find the user based on its socket.id from mongodb, and do some db operations, remove the socket.id from subscriber socket list and update back the list(array in mongodb) in the same column.
Now the problem is when there are concurrent requests.
All the callbacks finds the socketId
Then all the callbacks create the list of socketids excluding itself(as event is disconnect) and then all updates back to db.
Problem in this approch is that Even though result is expected as blank column I end up with socketIds, only one is removed.
Hope was able to explain. Can anybody please let me know what I am doing wrong here?? This seems to be a very common problem what is the standard approach of solving same.??
code snippit:
if(sSocketIds.length > 1){
console.log("{disconnect} session contains multiple socket processing for removing the current one");
var nSubscriberSocketids = [];
for(var cnt=0 ;sSocketIds.length>cnt ; cnt++){
if(sSocketIds[cnt]!=socket.id){
nSubscriberSocketids.push(sSocketIds[cnt]);
}
}
// This below line is problem I always end up with n-1 socketIds due to concurrency.
__db.SessionFrame.update({"_id":session._id },{"subscriberSocketIds":nSubscriberSocketids}, function(err,count){
if(err){
console.error("{disonnect} error while removing socket: "+socket.id);
}else{
console.log("{disconnect} subscriber socket removed successfully: socketId: "+socket.id+" session will still persist");
}
});
}

node.js tcp server, client and sent messages like merged

I've a node.js (tcp) server, i.e.
net.createServer
And I've a node.js client. I've created a module.export with a method
this.connect = function() {
var client = new net.Socket();
client.setTimeout(5000);
client.connect(settings.collectorport, settings.collectorhost, function() {
console.log('connected');
});
....
And another method, like
this.write = function(data, client) {
client.write(some-string);
}
From another node.js file, I invoke such methods from inside a loop like:
while (something) {
agent.write(data,client);
}
What happens is that sometimes the server receives, or the client send, two "some-string" all togheter.
I mean, if in the server I log what the server is receiving, I see, sometimes only one "message", sometimes two or three "messages" merged.
What can it be?
Sorry for my lexicon...
Assuming the number of messages you are sending matches the number of messages you are receiving/expecting on the other end, then I think what you're describing is basically how TCP works.
TCP is a stream and so you can't/shouldn't make any assumptions about "message boundaries." You could receive one byte or 10 kilobytes at a time, it just depends on the networking stack and some other factors, so you should be prepared to handle any amount of data that comes in (e.g. create a protocol, perhaps using a delimiter character, to sort out individual "messages").

Resources