Socket.io: RangeError:超出最大调用堆栈大小

创建于 2014-07-04  ·  32评论  ·  资料来源: socketio/socket.io

我只是在调用 `ìo.sockets.emit('hey', data); and it will crash with RangeError:超出最大调用堆栈大小. I use it in other places in my app and it works fine. I am not repeating this (checked with console). The logs say the error is in socket.io/node_modules/has-binary-data/index.js:46``。

我不知道问题出在哪里。 我尝试在使用它之前记录io.sockets并输出:

{ name: '/',
17:39:37 web.1  |   server:
17:39:37 web.1  |    { nsps: { '/': [Circular] },
17:39:37 web.1  |      _path: '/socket.io',
17:39:37 web.1  |      _serveClient: true,
17:39:37 web.1  |      _adapter: [Function: Adapter],
17:39:37 web.1  |      _origins: '*:*',
17:39:37 web.1  |      sockets: [Circular],
17:39:37 web.1  |      eio:
17:39:37 web.1  |       { clients: [Object],
17:39:37 web.1  |         clientsCount: 2,
17:39:37 web.1  |         pingTimeout: 60000,
17:39:37 web.1  |         pingInterval: 25000,
17:39:37 web.1  |         upgradeTimeout: 10000,
17:39:37 web.1  |         maxHttpBufferSize: 100000000,
17:39:37 web.1  |         transports: [Object],
17:39:37 web.1  |         allowUpgrades: true,
17:39:37 web.1  |         allowRequest: [Function],
17:39:37 web.1  |         cookie: 'io',
17:39:37 web.1  |         ws: [Object],
17:39:37 web.1  |         _events: [Object] },
17:39:37 web.1  |      engine:
17:39:37 web.1  |       { clients: [Object],
17:39:37 web.1  |         clientsCount: 2,
17:39:37 web.1  |         pingTimeout: 60000,
17:39:37 web.1  |         pingInterval: 25000,
17:39:37 web.1  |         upgradeTimeout: 10000,
17:39:37 web.1  |         maxHttpBufferSize: 100000000,
17:39:37 web.1  |         transports: [Object],
17:39:37 web.1  |         allowUpgrades: true,
17:39:37 web.1  |         allowRequest: [Function],
17:39:37 web.1  |         cookie: 'io',
17:39:37 web.1  |         ws: [Object],
17:39:37 web.1  |         _events: [Object] } },
17:39:37 web.1  |   sockets:
17:39:37 web.1  |    [ { nsp: [Circular],
17:39:37 web.1  |        server: [Object],
17:39:37 web.1  |        adapter: [Object],
17:39:37 web.1  |        id: 'RfgXeMgHeP_9SQC5AAAC',
17:39:37 web.1  |        client: [Object],
17:39:37 web.1  |        conn: [Object],
17:39:37 web.1  |        rooms: [Object],
17:39:37 web.1  |        acks: {},
17:39:37 web.1  |        connected: true,
17:39:37 web.1  |        disconnected: false,
17:39:37 web.1  |        handshake: [Object],
17:39:37 web.1  |        _events: [Object] },
17:39:37 web.1  |      { nsp: [Circular],
17:39:37 web.1  |        server: [Object],
17:39:37 web.1  |        adapter: [Object],
17:39:37 web.1  |        id: '7TEjGJjWzxObulClAAAD',
17:39:37 web.1  |        client: [Object],
17:39:37 web.1  |        conn: [Object],
17:39:37 web.1  |        rooms: [Object],
17:39:37 web.1  |        acks: {},
17:39:37 web.1  |        connected: true,
17:39:37 web.1  |        disconnected: false,
17:39:37 web.1  |        handshake: [Object],
17:39:37 web.1  |        _events: [Object] } ],
17:39:37 web.1  |   connected:
17:39:37 web.1  |    { RfgXeMgHeP_9SQC5AAAC:
17:39:37 web.1  |       { nsp: [Circular],
17:39:37 web.1  |         server: [Object],
17:39:37 web.1  |         adapter: [Object],
17:39:37 web.1  |         id: 'RfgXeMgHeP_9SQC5AAAC',
17:39:37 web.1  |         client: [Object],
17:39:37 web.1  |         conn: [Object],
17:39:37 web.1  |         rooms: [Object],
17:39:37 web.1  |         acks: {},
17:39:37 web.1  |         connected: true,
17:39:37 web.1  |         disconnected: false,
17:39:37 web.1  |         handshake: [Object],
17:39:37 web.1  |         _events: [Object] },
17:39:37 web.1  |      '7TEjGJjWzxObulClAAAD':
17:39:37 web.1  |       { nsp: [Circular],
17:39:37 web.1  |         server: [Object],
17:39:37 web.1  |         adapter: [Object],
17:39:37 web.1  |         id: '7TEjGJjWzxObulClAAAD',
17:39:37 web.1  |         client: [Object],
17:39:37 web.1  |         conn: [Object],
17:39:37 web.1  |         rooms: [Object],
17:39:37 web.1  |         acks: {},
17:39:37 web.1  |         connected: true,
17:39:37 web.1  |         disconnected: false,
17:39:37 web.1  |         handshake: [Object],
17:39:37 web.1  |         _events: [Object] } },
17:39:37 web.1  |   fns: [],
17:39:37 web.1  |   ids: 0,
17:39:37 web.1  |   acks: {},
17:39:37 web.1  |   adapter:
17:39:37 web.1  |    { nsp: [Circular],
17:39:37 web.1  |      rooms:
17:39:37 web.1  |       { '5MGPNOdO4th_dOuZAAAA': [],
17:39:37 web.1  |         '64rUhxxp--4Qk1MqAAAB': [],
17:39:37 web.1  |         RfgXeMgHeP_9SQC5AAAC: [Object],
17:39:37 web.1  |         '7TEjGJjWzxObulClAAAD': [Object] },
17:39:37 web.1  |      sids:
17:39:37 web.1  |       { RfgXeMgHeP_9SQC5AAAC: [Object],
17:39:37 web.1  |         '7TEjGJjWzxObulClAAAD': [Object] },
17:39:37 web.1  |      encoder: {} },
17:39:37 web.1  |   _events: { connection: [Function] } }

我的代码是:

`````` JAVASCRIPT

if (game.scoreTeamTwo > game.scoreTeamOne && game.scoreTeamTwo > game.scoreTeamThree && game.scoreTeamTwo > game.scoreTeamFour) {
game.winner = 2;
io.sockets.emit('CTFEnd', 游戏);
}

//它只是查看团队 1 是否赢了比赛,当它赢了时会发出CTFEnd和所有其他游戏数据
``````

最有用的评论

这可能是因为您试图发送一个带有循环引用的对象,导致递归调用超出堆栈大小。

所有32条评论

找到了我的问题的“解决方案”。 我可以发送分散的每条数据,但它不适用于对象

我最近也遇到了这个错误,唯一的区别是它只是偶尔发生在我身上。 整个上午都在测试,但我无法复制该问题。

对我来说,只有当 obj 很大时,它才无法向所有人发射。

@BenBals如果对象太大,那么一个不错的解决方法是以字符串的形式发送它,即在它上面运行JSON.stringify()

我有另一个工作,但我考虑过。

:cry: 调查这个

发出类型的对象时有同样的问题:
{success: file, content: file.content} 其中 file.content 是 Buffer 对象,file 的所有其他属性都是字符串。

必须将字段内容直接添加到对象中,因为 hasBin() 只检查对象的第一级。 但是当它尝试发送缓冲区时,它得到了“最大调用堆栈超出”

您可以通过发出套接字对象(至少是一种方式)来复制它,所以(下面是 server to -> client )

socket.emit('crash', {socket:socket});

我很好奇这是否有实际修复。

关于那个问题的任何更新?
编辑:我的问题是我试图发送递归对象。

有趣的是,在尝试将我的 Firebase 数据传递给客户端时,我遇到了同样的错误。

错误

node_modules/socket.io/node_modules/has-binary-data/index.js:46

for (var key in obj) {
                ^
RangeError: Maximum call stack size exceeded

服务器端

var DB = new Firebase('https://1234abcd.firebaseIO.com');
var USERS = DB.child("users");

io.sockets.on('connection', function(socket){

    socket.emit('test', {
        db: USERS
    });

});

寻找解决方案...

对不起,但我的中文不是很好。 你能不能把这个翻译成英文。

做了谷歌翻译,结果是“找到解决方案......”......几乎不值得回应。 作为记录,解决方案是不要通过 socket.io 传递如此大量的数据……这是一个专为快速、简短响应而设计的套接字。 分解您的回复或通过 ajax 发送。 取消订阅此线程。

有一件事socket.io代码可以做的就是异步迭代象对象及其属性,事情:

var props = [];
var obj = { a: 1, b:2, c: { d: 3, e: 4 } };

function next_prop(callback){
  if (!props.length){
    setTimeout(callback);
    return;
  }
  var prop = props.shift();
  //do whatever with the prop, call parse_obj on it if it's an object
  setTimeout(next_prop);
}

function parse_obj(obj, callback){
  for (var i in obj){
    props.push(i);
  }
  setTimeout(function(){next_prop(callback);});
}

parse_obj(obj);

当然,这不是您应该使用的实际代码,因为需要为每个单独的对象包装函数,以防它们被嵌套,否则您将与正在解析的对象发生冲突。

我也收到了那个错误,我的代码就像:“io.sockets.emit('key', data);”
我尝试简化“数据”对象并保持它很小,并且它起作用了。
--AND,我查看了 src 代码,发现了这个:

image_20150306180547

当您的“数据”对象具有递归属性引用时,此代码将崩溃。
例如proto > proto > proto ...

+1 核心团队是否喜欢二进制检查的异步版本,我可以帮助获得该设置

我可以通过发送套接字对象来重现问题:)

+1 IE11 在 _hasBinary 中显示“堆栈空间不足”。

当我尝试将整个套接字对象发送回客户端时,此错误显示给我。 我_真正_需要的是socket.id所以当我发回一个较小的项目时错误消失了——在我的例子中,是socket.id而不是整个socket对象

这可能是因为您试图发送一个带有循环引用的对象,导致递归调用超出堆栈大小。

@LordMajestros那为我修好了! 谢谢

@GerbenHofman不客气

我在 NodeJS v4.4.4 和 socket.io v1.4.5 上遇到了同样的错误。

就我而言,它发生在断开连接事件之后。
只有当我调用socket.emit超过 200,000 次时才会发生这种情况。

如果调用socket.emit的次数在 100,000 左右,则不会发生此错误。

我与emit一起使用的参数始终是字符串

这些信息对您有帮助吗?

只是为了添加到@shunjikonishi ,一旦我通过 io.emit 发送100,000 个事件,我就会看到这种情况发生。 我有 1 个连接的袜子,所以 100,000 似乎是一个硬上限。

似乎这是 Node(或 JavaScript 运行时)强加的限制,并且 Socket.io 每次调用时都会持有对某些内容的引用,因此当您点击第 100,000 次时,它就会倒下。

使用 Node 5.11.0 和 Socketio 1.4.8 进行测试。 我的 Node 版本(以及我的操作系统等,真的不知道这 100,000 来自哪里)与@shunjikonishi 不同,这可以解释为什么我达到了 100,000 的限制而他达到了 200,000。

我使用 ws.js 运行了完全相同的代码,它运行良好,超过 100,000 个套接字发出没有问题,所以可能是 Socket.io 的问题。

Socket IO 是否有可能实现防止递归数据发出并因此错误而失败的防护措施? 一个简单的检测可以防止这个错误的发生,而是发出一个更有意义的错误,比如“你可能正在尝试发送循环数据”。 这将使调试更容易。

检测循环数据有很多不错的解决方案: https :

一种简短的解决方案依赖于 JSON.stringify 来查找问题:

function isObjectCircular(obj) {
    try {
        JSON.stringify(circularReference);
    } catch(err) {
        return (err.toString() === 'TypeError: Converting circular structure to JSON');
    }
    return false;
}

更多详情: https :

@adamreisnz欢迎您提出 PR ;)

当有人在我发表评论 5 个月后提到我时,总是让我措手不及 😆

我也遇到了这个错误。 这就是为什么我要浪费两个小时来检查我的整个代码:<。
我认为它是由像 A={B:{C:A}} 这样的递归对象引起的,显然socket是一个递归对象。
事实上,我猜这是因为在 buffer.js 中,他们使用递归来查找您要发送的数据长度。 然后得到“超出最大调用堆栈大小”。 如果他们使用 JSON.stringify() 来获取长度,则会出现另一个关于“圆形结构”的明显错误。 顺便说一句,它对谷歌有一个不好的关键词!

我也刚碰到这个。

如果尝试发送具有循环引用的对象, hasBin将用递归循环填充堆栈。

Shucks,我看到有一个已经开放了 2 年的 PR 可以解决这个问题:

@dustingraham修复看起来很棒,但我不确定性能影响。

另外,即使它不再抛出hasBinary方法,恐怕代码后面调用的 JSON.stringify 方法仍然会抛出错误:

> var a = {};
undefined
> var b = { a: a };
undefined
> a.b = b
{ a: { b: [Circular] } }
> JSON.stringify(a)
Thrown:
TypeError: Converting circular structure to JSON
    at JSON.stringify (<anonymous>)
此页面是否有帮助?
0 / 5 - 0 等级

相关问题

denisu picture denisu  ·  53评论

shivajivarma picture shivajivarma  ·  37评论

ghost picture ghost  ·  38评论

runvnc picture runvnc  ·  73评论

ForgeableSum picture ForgeableSum  ·  48评论