Node.js + Socket.io 超出最大调用堆栈大小

Posted

技术标签:

【中文标题】Node.js + Socket.io 超出最大调用堆栈大小【英文标题】:Node.js + Socket.io Maximum call stack size exceeded 【发布时间】:2015-02-07 04:51:10 【问题描述】:

对于我的 Node 应用程序,我有一个在 Debian 上运行的服务器 (app.js),它使用 socket.io 为我的客户端 (index.html) 提供 html 和 websocket 数据。我正在尝试制作一款基于回合制的 HTML5 多人游戏。

在使用 socket.emit()/io.emit() 和 socket.on() 执行多次成功的数据传输后,我的服务器在 socket.emit() 调用时崩溃并出现错误 “事件.js:72 投掷者; //未处理的“错误”事件 RangeError:超出最大调用堆栈大小”。 我有很多 socket.on() 事件侦听器,每个侦听器都处理游戏中的不同功能(例如 roll_dice、end_turn、ready_to_play 等)。

我试图研究这个问题(发现很多关于异步循环的讨论),但无法找到如何将解决方案应用于我自己的代码。我在这里附上了相关来源。你也可以在我的 github 上查看所有源代码: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));
  );
);

请轻点,我大约一周前才开始使用 Node.js。谢谢!

【问题讨论】:

你能发布完整的错误信息吗? 编辑问题以包含它,它是:“events.js:72 throw er; //Unhandled 'error' event RangeError: Maximum call stack size exceeded”。 【参考方案1】:

找到我的问题。

我试图通过网络发送的对象(temp)(在 socket.emit('roll_result',temp); 中)是一个自引用数组。正是数组的递归属性导致堆栈超出了最大大小。

【讨论】:

感谢您添加问题的原因,只是在尝试通过 socket.io 连接发送自递归对象时遇到了同样的问题,并且不知道是什么导致了最大调用堆栈大小被超越! 哇,今天也遇到了这个问题!如果我没有发现这篇文章,可能又过了一年。大声笑 非常感谢,您解决了我的问题!【参考方案2】:

答案很有帮助。谢谢。

我刚遇到同样的问题,想与可能遇到它的任何人分享。

我的代码使用 express.js 并具有以下内容:

io = require('socket.io').listen(server);
......
io.to(socketId).emit('hello', userId:userId, data:data, res:res);

它产生了“超出最大调用堆栈”错误。问题是我不应该通过 socketio 将变量“res”发送给客户端。我想如果我这样做会导致一些递归行为。

解决方案只是从 emit 语句中删除“res”:

io.to(socketId).emit('hello', userId:userId, data:data);

【讨论】:

【参考方案3】:

我有同样的问题。 对我来说,问题是我在套接字上发出的对象包含对套接字本身的引用。所以我基本上是在套接字内发送一个套接字。不要在家里尝试这个:)

【讨论】:

【参考方案4】:

当我点击提交按钮时,我遇到了同样的错误。它被禁用并抛出“超出最大调用堆栈大小”。我重新启动了浏览器,它起作用了..奇怪的行为

【讨论】:

【参考方案5】:

我想分享我在同一问题上的错误:

    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");
    );


在关闭事件中,使用正常函数和this(错误原因)导致关闭事件发出循环,结果是堆栈大小错误。

    this.client.on("close", () => 
        this.emit("close");
    );

使用箭头函数。 (或将真实的 this 复制到 _this 之类的东西中并使用内部函数)解决了问题。

这实际上是对函数上下文(在回调中)的无知,或者疏忽..

【讨论】:

【参考方案6】:

我遇到了同样的问题,因为我发送了 3 个对象,我通过只发送一个对象解决了这个问题

【讨论】:

【参考方案7】:

我也遇到了同样的问题,但就我而言,这有点有趣,因为我实际上是在我的 catch 块中发出错误事件 socket.on("error", new Error(err))。由于error 是一个私人事件,因此只需更改发出的事件即可修复它。哈哈

【讨论】:

【参考方案8】:

就我而言,我不小心通过 socket.io 发送了Promise

【讨论】:

【参考方案9】:

我在使用 Socket.io、express 服务器和 p5.js 库制作实时白板应用程序时遇到了同样的问题。 我试图使用套接字将 p5 矢量发送到服务器,导致错误。

这是我的代码 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);

^ 上面的代码会抛出一个错误,因为我要发送的数据对象包含 txtPos(p5 vector),其中包含 p5 对象,其中包含 p5 向量,p5 向量再次包含 p5 对象,并且它会永远持续下去。 ..就像一个递归对象(循环对象)。

要解决这个问题,我的新代码非常简单。

我换了

pos:txtPos,

pos: x:txtPos.x, y:txtPos.y, 猜猜我现在能够成功发送这些数据。 :D

【讨论】:

虽然你遇到的错误很相似,但问题和解决方案的上下文与OP的问题不同。此外,它不会为现有答案增加任何新价值。请考虑遵循答案指南:vi.stackexchange.com/help/how-to-answer。最好的。

以上是关于Node.js + Socket.io 超出最大调用堆栈大小的主要内容,如果未能解决你的问题,请参考以下文章

Node.js + Socket.io 内存泄漏和最大监听器

Node.js + socket.io 确定每个实例的最大客户端数量

使用sockets.io超出了node.js调用堆栈

如何验证来自 socket.io 的数据包?

未找到 Socket.io.js(node.js + express + socket.io)

socket.io 中最大同时打开的房间