Reputation: 1101
For my Node application, I have a server (app.js) running on Debian serving both html and websocket data using socket.io to my client (index.html). I am attempting to make a turn-based HTML5 multiplayer game.
After performing a number of successful data transmissions using socket.emit()/io.emit() and socket.on(), my server crashes on an socket.emit() call with the error
"events.js:72
throw er; //Unhandled 'error' event
RangeError: Maximum call stack size exceeded".
I have quite a few socket.on() event listeners, with each one handling a different function in the game (e.g. roll_dice, end_turn, ready_to_play, etc.).
I attempted researching the problem (found a lot of discussion on async loops), but was unable to find how to apply the solutions to my own code. I attached relevant source here. You can also view all the source on my github at: https://github.com/sjmoon0/gameofdeath
index.html
var socket = io.connect('http://131.178.15.173',{'forceNew':true});
...
//----------------Initialization and Menu functions-----------
socket.on('load', function (data) {
console.log(data);
clientID=data;
socket.emit('check_game_started', { un: clientID });
socket.on('last_client_loaded', function(hasStarted){
console.log("Has game started? :"+hasStarted);
if(hasStarted==true){
$('#choosecharacter').show();
}
});
});
socket.on('client_disconnect', function (data) {
console.log(data);
});
socket.on('client_counter', function (data) {
if(data<5){
console.log(data);
incrementLoadBar(data);
allowedInGame=true;
}
if(!allowedInGame){
...
}
});
socket.on('game_started', function (data) {
console.log(data);
$('#welcome').hide();
$('#choosecharacter').show();
});
socket.on('set_user', function(characterName){
chosenCharacter=characterName;
});
socket.on('disable_player_choice', function(data){
var id=data.stuff[0].chara;
incrementLoadBar(data.stuff[0].numChar);
console.log(id +" was chosen");
$('#'+id).hide();
});
//-------------------Gameplay functions
socket.on('start_gameplay',function(nonsense){
showChanges(nonsense);
$('#wait').hide();
$('#gamespace').show();
draw_c();
socket.emit('ready_to_play',chosenCharacter);
});
socket.on('take_turn',function(updatedBoard){
showChanges(updatedBoard);
if(updatedBoard.currPlayer==chosenCharacter){
promptUser(updatedBoard);
}
});
socket.on('roll_result',function(rollResult){
promptUser(rollResult);
});
...
$('#rollDiceButton').click(function(){
socket.emit('roll_dice',chosenCharacter);
});
$('#okCloseButton').click(function(){
socket.emit('end_turn',chosenCharacter);
});
$('.thumbnail').click(function(something){
socket.emit('player_chosen', something.target.id);
...
});
app.js
var app = require('http').createServer(handler)
var io = require('socket.io')(app);
var fs = require('fs');
var url = require('url');
...
app.listen(8001);
function handler (req, res) {
...
}
console.log("~Server Running~");
io.on('connection', function (socket) {
console.log("A Client connected");
...
socket.emit('load', { user: uID });
io.emit('client_counter',numClients);
if(numClients==4){
gameStarted=true;
console.log("Game started!");
io.emit('game_started',"The Game has begun!");
}
else if(numClients>4){
numClients--;
delete allClients[allClients.indexOf(socket)];
}
socket.on('check_game_started', function (data) {
socket.emit('last_client_loaded', gameStarted);
console.log(data);
if(gameStarted){
console.log("Last Player Loaded!");
}
});
socket.on('player_chosen', function(cp){
...
socket.emit('set_user', cp);
...
io.emit('disable_player_choice',{'stuff':[{'chara':cp,'numChar':numCharChosen}]});
if(numCharChosen==4){
io.emit('start_gameplay', boardUpdate);
}
});
socket.on('disconnect',function(){
console.log("A client disconnected");
numClients--;
delete allClients[allClients.indexOf(socket)];
io.emit('client_disconnect',"We've lost another comrade!");
});
socket.on('ready_to_play',function(characterThatIsReadyToPlay){
io.emit('take_turn',boardUpdate);
});
socket.on('roll_dice', function(characterThatRolledDice){
var temp=generateRollResult(characterThatRolledDice)
socket.emit('roll_result',temp);
});
socket.on('end_turn',function(characterThatEndedTurn){
io.emit('take_turn',nextUpdate(characterThatEndedTurn));
});
});
Please be gentle, I just started using Node.js about a week ago. Thanks!
Upvotes: 24
Views: 29485
Reputation: 368
In my case, I was accidentally sending a Promise
through socket.io
Upvotes: 0
Reputation: 181
I ran into the same problem while i was making a real-time whiteboard application using Socket.io, express server and p5.js library. i was trying to send the p5 vector using socket to the server whick caused the error.
Here is my code
txtPos = createVector(mouseX / width, mouseY / height); let data = { pos: txtPos, txt: "", h: colorSlider.value(), b: brighSlider.value(), size: sizeSlider.value(), }; texts.push(data); socket.emit("newText", data);
^ The above code throws an error as the data object i wanted to send was including the txtPos(p5 vector) which includes the p5 object, which includes the p5 vector, which again includes the p5 object and it goes on forever...like a recursive object(circular object).
to fix this my new code was pretty simple.
I replaced
pos:txtPos,
with
pos:{ x:txtPos.x, y:txtPos.y, }
and guess what now i am able to send this data successfully. :D
Upvotes: -1
Reputation: 297
I had the same issue too, but in my case it's a bit funny because I actually was emitting the error event socket.on("error", new Error(err))
in my catch
block. It was fixed with just changing the emitted event because error
is a private event. LOL
Upvotes: 0
Reputation: 688
I had the same problem, it happened because I was sending 3 objects with the emit I solved it by sending only one object
Upvotes: 0
Reputation: 103
I had the same issue. For me the problem was that the object I was emitting on the socket held a reference to the socket itself. So I was basically sending a socket inside a socket. Don't try this at home :)
Upvotes: 5
Reputation: 19
I would like to share my mistake on the same issue:
public createClient() {
this.client = new net.Socket();
this.client.connect(this.port, this.ip, () => {
this.emit("connect");
});
this.client.on("data", (data) => {
this.emit("data", data);
});
this.client.on("close",function () => {
this.emit("close");
});
}
in close event, using normal function and this ( cause of error ) cause a loop of close event emit and the result is stack size error .
this.client.on("close", () => {
this.emit("close");
});
Using arrow func. ( or copying real this into something like _this and using inside function ) solved issue.
This is actually being ignorant about function context ( in callback ), or negligence ..
Upvotes: 0
Reputation: 2177
This is the same error I came across, When I clicked on submit button. It was getting disabled and throwing "Maximum call stack size exceeded". I restarted my browser, It worked.. Strange behaviour
Upvotes: 0
Reputation: 201
The answer is very helpful. Thanks.
I just had the same issue and want to share with anyone who might encounter it.
My code uses express.js and has the following:
io = require('socket.io').listen(server);
......
io.to(socketId).emit('hello', {userId:userId, data:data, res:res});
It generated the "Maximum call stack exceeded" error. The problem is that I should not send the variable 'res' over the socketio to the client. I guess it will cause some recursive behavior if I do so.
The solution is just remove the 'res' from the emit statement:
io.to(socketId).emit('hello', {userId:userId, data:data});
Upvotes: 11
Reputation: 1101
Found my issue.
The object (temp) I was trying to send over the network (in socket.emit('roll_result',temp);) was a self-referencing array. It was the recursive property of the array that caused the stack to exceed the max size.
Upvotes: 76