Socket.IO, multiple connections on page load - node.js

I have a socketIO/express app that goes like this :
function joinRoom(socket,roomName){
socket.join(roomName);
console.log('success joining '+roomName);
socket.broadcast.to(roomName).emit('chat',{type:'join',msg:guestList[socket.id]+' has arrived in '+roomName+'!'});
socket.emit('chat',{type:'join',msg:'You are now in '+roomName});
}
function assignName(socket){
var name = 'Player#'+guestId;
guestList[socket.id]= name;
socket.emit('chat',{type:'name',msg:name});
return guestId+1;
}
io.sockets.on('connection', function (socket) {
io.of('/lobby').on('connection', function (socket) {
guestId=assignName(socket);
joinRoom(socket, 'Lobby');
});
handleMessage(socket);
});
When I open a first browser window, everything goes well, I see Player#0 connected, and the join room msg. However, when I open a second window or browser, I see 2 connections (player#1 and #2), then if I open a 3rd window, i will see 3 connections, #3,#4,#5. What the heck? It has to be something stupid but I can't figure it out, Help!
G.

Sorted!
Basically, I separated the namespace connection from the io.sockets.on(...) and behaviour went back to normal. It makes sense, although I'm not sure why the number of connect events was incremental...

Related

Socket: When player in a room closes browser, how server can correctly emit to other sockets in that room?

Please, read to the end, help me!
I'm developing a multiroom game using SocketIO, with a client-side (React) and a server-side (Node). I'm having a problem on handling this situation:
Consider that at least two clients are inside a Room, after have joining it with socket.join(roomId) (at server-side).
Situation 1: When a player leaves the room manually (clicking a button in the page), the client-side does socket.emit("playerLeaving", someVar) to the server-side listener socket.on("playerLeaving", doStuff) that do some important things with the database (let's call it X listener). Then this listener fires back an event to the other client sockets in that room, with io.sockets.in(roomID).emit("playerLeft", someVar). No problem here.
Situation 2: Instead of manually leaving that room, that user just close the tab/browser, which fires a "disconnect" event do the server-side. Event in that case, the server must do the same procedure that he did on 1st situation, inside that X listener, so I just tried to emit this event socket.emit("playerLeaving", roomID) from inside the "disconnect" handler at server-side, so the X listener would receive it, do his stuffs, and broadcast to the other players that someone has left that room.
THE PROBLEM: the "disconnect" handler (at server-side) emits to X listener (also server-side), but this one doesn't receives it. Summin up, when a player in a room closes the tab/browser, the server isn't handling it correctly and consequently the other players in that room doesn't even get to know about that.
MY CODE:
SERVER-SIDE:
io.sockets.on('connection', (socket) => {
socket.on("playerJoiningRoom", (roomID) => {
socket.join(roomID); // to sign socket to a room
// .... some code
io.broadcast.to(roomID).emit("someoneJoined", someVar); // this works fine
})
// X-listener
socket.on("playerLeaving", (someVar) => {
// ... do stuff in database
io.sockets.in(roomID).emit("playerLeft", otherVar);
}
socket.on("disconnect", () => {
// ...some code here
// then, emit to the listener above
// example: socket.emit("playerLeaving", someVar);
});
})
}
CLIENT-SIDE
function socketEnteredRoom(socket, roomID) {
// notify server
socket.emit("playerJoiningRoom", roomID);
// listen to other players joining the room
socket.on("someoneJoined", someVar);
// listen to other players leaving the room. This listener works when some player leave manually (leave button), but don't work when a player closes tab/browser
socket.on("someoneLeft", someVar);
}
// when player wants to exit room
function handlerExitRoom() {
socket.emit("playerLeaving", someVar);
}
Waiting for your help! Thank you!
(sorry if this is a repeated question, but I couldn't find a answer that worked)
I'm not sure since I can't see your full code, but a common issue is people try to emit to rooms their socket is in in disconnect but the socket is no longer in any rooms at this point. Try changing to disconnect to disconnecting.
Try this,
//server-side
socket.on("disconnect", () => {
io.emit("playerLeaving", someVar);
});
//client-side
socket.emit("disconnect", () => {
});

This "if else" statement don't work in my socket.io/Node.js environment

So I am developing a simple game. The logic flow is when 2 players connect to the room, the game will initialize and emit a 3 seconds countdown event alongside with a button . if one player clicks the button, that player will emit an event making him/her the host of the game.
The button will appear for 3 seconds. If it disappear without being clicked, the server will randomly pick the host.
Whether or not the button is clicked,after 3 seconds all clients will emit a "ready" event.
Here is my code.
if the button is clicked, the "host" event will be emitted by the client,and my server side code is
client.on('host',function(){
var player = room.getPlayer(client.id);
player.isHost=true;
});
Then here is the server side for the "ready" event.
client.on("ready", function() {
var player = room.getPlayer(client.id);
var table = room.getTable(player.tableID);
if (2>1) {
for (var i = 0; i < table.players.length; i++) {
if (table.players[i].isHost===true){
console.log("you are the host")
} else {
console.log("we are going to randomly pick a host")
}
}
}
})
Now if no players click the button the terminal will show
we are going to randomly pick a host
we are going to randomly pick a host
we are going to randomly pick a host
we are going to randomly pick a host
Otherwise it will be like
we are going to randomly pick a host
you are the host
we are going to randomly pick a host
you are the host
At this stage only 2 clients are allow for the game so the players.length is 2.It seems like the if/else will be executed same time as the players.length?
I think the first thing to mention is that the if (2>1) { ... is completely unnecessary. The code will simply go through to the for loop as if it's not there.
Your code besides the if statement, is honestly ok. There's nothing that screams 'I cause more loops then necessary'. At this point I would suggest posting anything in the project related to:
Multithreading
Socket Handling / connecting the socket outside of this
I believe more information is due.
Thanks for the helps. Yes the for loop is not necessary and it is the cause of the problem. My solution is to detach it from the if-else statement.
for (var i = 0; i < table.players.length; i++) {
}
//test if Host exit in the table
if (table.ifHost===true){
console.log("you are the host")
} else {
var randomNumber = Math.floor(Math.random() * table.playerLimit);
var Host=table.players[randomNumber]
}
The interesting thing I found out about the socket io is when two sockets fire this event, if Host doesn't exit,the first one will execute the else(noHost) and then create a Host. The second socket will execute the if condition as the host was created by the previous socket....

I do not want to run socket.emit until I am ready to use it

So I don't want to fetch from the server socket.emit until I need it. Because everything is not prepared fully until then. How do I have socket.emit sit quietly until I am ready for it?
Server
io.sockets.on('connection', function (socket) {
socket.on('adduser', function(player){
........
}
socket.emit('getQ', socket.Ques[0].question);
]
Client
var retrieveQ = function (){
socket.on('getQ', function(quesPick){
quesObj = quesPick;
})
The client is retrieveQ much later on its not suppose to be done at start, yet socket is emitting almost right away and giving me errors because socket.Ques is not made until later on.
Simple, emit getQ on response to a client request after client socket connects. Something like this:
io.sockets.on('connection', function (socket) {
socket.on('adduser', function(player){
........
}
socket.on('askGetQ', function(zzz){
socket.emit('getQ', socket.Ques[0].question);
}
}
On the client do:
io.on('connection', function(socket){
socket.emit('getQ', 'something');
});
node.js is an event driven environment. So, sometime in the future there will be some sort of event on your server that will cause you to want to send this .emit(). At that point, you need to be able to find the appropriate socket object and then use it to send the .emit().
Since you haven't said exactly what event you want to use to send this emit, we can't really help more specifically. If you care to explain that, we could probably offer specific code.
On the client you should do:
const chat = io.connect('http://localhost/chat')
chat.on('connect', function () {
chat.emit('getQ', socket.Ques[0].question);
});

node.js + socket.IO - socket not reconnecting?

I know socket.io has a built in feature for reconnecting and everything, however I don't think that it is working - as I have seen from others it's also not working for them either.
If a user puts their computer to sleep, it disconnects them, and then when they open it back up they are no longer connected so they don't any of the notifications or anything until they refresh the page. Perhaps it's just something that I'm not doing correctly?
var io = require('socket.io').listen(8080);
var users = {};
////////////////USER CONNECTED/////
console.log("Sever is now running");
io.sockets.on('connection', function (socket) {
//Tell the client that they are connected
socket.emit('connected');
//Once the users session is recieved
socket.on('session', function (session) {
//Add users to users variable
users[socket.id] = {userID:session, socketID:socket};
//When user disconnects
socket.on('disconnect', function () {
//socket.socket.connect();
var count= 0;
for(var key in users){
if(users[key].userID==session)++count;
if(count== 2) break;
}
if(count== 1){
socket.broadcast.emit('disconnect', { data : session});
}
//Remove users session id from users variable
delete users[socket.id];
});
socket.on('error', function (err) {
//socket.socket.connect();
});
socket.emit("connection") needs to be called when the user reconnects, or at least the events that happen in that event need to be called.
Also socket.socket.connect(); doesn't work, it returns with an error and it shuts the socket server down with an error of "connect doesn't exist".
The problem is related to io.connect params.
Look at this client code (it will try to reconnect forever, with max delay between attempts 3sec):
ioParams = {'reconnection limit': 3000, 'max reconnection attempts': Number.MAX_VALUE, 'connect timeout':7000}
socketAddress = null
socket = io.connect(socketAddress, ioParams)
There are two important parameters out there, related to your problem:
reconnection limit - limit the upper time of delay between reconnect attemts. Normally it's getting bigger and bigger in time of server outage
max reconnection attempts - how many times you want to try. Default is 10. In most cases this is the problem why the client stops trying.

How can i handle Close event in Socket.io?

I'm making simple online game which based on Web.
the game uses Socket.io for netwoking each other.
but I encountered the problem.
think about following situation .
I ran Socket.io server.
one player making the room , and other player join the room.
they played game some time ..
but one player so angry and close the game tab.
in this situation , how can I get the event which one client have been closed the browser in server-side ?
according to googling , peoples say like this : "use browser-close event like onBeforeUnload"
but I know that All browser don't support onBeforeUnload event. so i want solution about
checking the client disconnection event in SERVER SIDE.
in Socket.io ( nodeJS ) server-side console , when client's connection closed , the console say like following :
debug - discarding transport
My nodeJS version is 0.4.10 and Socket.io version is 0.8.7. and both are running on Linux.
Anyone can help please ?
shortend codes are here :
var io = require ( "socket.io" ).listen ( 3335 );
io.sockets.on ( "connection" , function ( socket )
{
socket.on ( "req_create_room" , function ( roomId )
{
var socketInstance = io
.of ( "/" + roomId )
.on ( "connection" , function ( sock )
{
sock.on ( "disconnect" , function ()
{
// i want this socket data always displayed...
// but first-connected-client doesn't fire this event ..
console.log ( sock );
}
});
});
});
Update: I created a blog post for this solution. Any feedback is welcome!
I recommend using the 'sync disconnect on unload' option for Socket IO. I was having similar problems, and this really helped me out.
On the client:
var socket = io.connect(<your_url>, {
'sync disconnect on unload': true });
No need to wire in any unload or beforeunload events. Tried this out in several browsers, and its worked perfectly so far.
There's an event disconnect which fires whenever a socket.io connection dies (note that you need this, because you may still have a wep page open, but what if your internet connection dies?). Try this:
var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
socket.on('disconnect', function () {
io.sockets.emit('user disconnected');
});
});
at your server. Taken from Socket.IO website.
//EDIT
So I looked at your code and did some tests at my place. I obtained the very same results as you and here's my explanation. You are trying to make Socket.IO very dynamic by dynamically forcing it to listen to different urls (which are added at runtime). But when the first connection is made, at that moment the server does not listen to the other url. It seems that exactly at that point (when connection is accepted) the disconnect handler is set for the first connection and it is not updated later (note that Socket.IO does not create new connections when you call io.connect many times at the client side). All in all this seems to be a bug! Or perhaps there is some fancy explanation why this behaviour should be as it is but I do not know it.
Let me tell you some other things. First of all this dynamical creation of listeners does not seem to be a good way. In my opinion you should do the following: store the existing rooms and use one url for all of them. Hold the ID of a room and when you emit for example message event from client add the ID of a room to the data and handle this with one message handler at the server. I think you get the idea. Push the dynamic part into the data, not urls. But I might be wrong, at least that's my opinion.
Another thing is that the code you wrote seems to be bad. Note that running .on('connection', handler) many times will make it fire many times. Handlers stack one onto another, they do not replace each other. So this is how I would implement this:
var io = require("socket.io").listen(app);
var roomIds = [];
function update_listeners(id) {
io.of("/"+id).on("connection", function(socket) {
console.log("I'm in room " + id);
socket.on("disconnect", function(s) {
console.log("Disconnected from " + roomId);
});
});
}
var test = io.sockets.on("connection", function(socket) {
console.log("I'm in global connection handler");
socket.on("req_create_room", function(data) {
if (roomIds.indexOf(data.roomId) == -1 ) {
roomIds.push(data.roomId);
update_listeners(data.roomId);
}
test.emit("room_created", {ok:true});
});
socket.on("disconnect", function(s) {
console.log("Disconnected from global handler");
});
});
Keep in mind that the problem with creating connections before the listeners are defined will still occure.

Resources