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] } }

๋‚ด ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

`````` ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ

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 ๊ฐ์ฒด์ด๊ณ  ํŒŒ์ผ์˜ ๋‹ค๋ฅธ ๋ชจ๋“  ์†์„ฑ์€ ๋ฌธ์ž์—ด์ž…๋‹ˆ๋‹ค.

hasBin()์€ ๊ฐ์ฒด์˜ ์ฒซ ๋ฒˆ์งธ ์ˆ˜์ค€๋งŒ ํ™•์ธํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•„๋“œ ๋‚ด์šฉ์„ ๊ฐ์ฒด์— ์ง์ ‘ ์ถ”๊ฐ€ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฒ„ํผ๋ฅผ ๋ณด๋‚ด๋ ค๊ณ  ํ•  ๋•Œ '์ตœ๋Œ€ ํ˜ธ์ถœ ์Šคํƒ ์ดˆ๊ณผ'๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

์†Œ์ผ“ ๊ฐ์ฒด๋ฅผ ๋‚ด๋ณด๋‚ด์–ด ์ด๋ฅผ ๋ณต์ œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์ ์–ด๋„ ํ•œ ๋ฐฉํ–ฅ). (์•„๋ž˜๋Š” ์„œ๋ฒ„์—์„œ -> ํด๋ผ์ด์–ธํŠธ๋กœ)

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);"์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.
๋‚˜๋Š” "๋ฐ์ดํ„ฐ"๊ฐ์ฒด๋ฅผ ๋‹จ์ˆœํ™”ํ•˜๊ณ  ์ž‘๊ฒŒ ์œ ์ง€ํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•˜๊ณ  ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค.
--๊ทธ๋ฆฌ๊ณ , src ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๊ณ  ๋‹ค์Œ์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค.

image_20150306180547

"๋ฐ์ดํ„ฐ" ๊ฐœ์ฒด์— ์žฌ๊ท€ ์†์„ฑ ์ฐธ์กฐ๊ฐ€ ์žˆ์œผ๋ฉด ์ด ์ฝ”๋“œ๊ฐ€ ์ถฉ๋Œํ•ฉ๋‹ˆ๋‹ค.
์˜ˆ: ํ”„๋กœํ†  > ํ”„๋กœํ†  > ํ”„๋กœํ†  ...

+1 ์ด์ง„ ๊ฒ€์‚ฌ์˜ ๋น„๋™๊ธฐ ๋ฒ„์ „๊ณผ ๊ฐ™์€ ํ•ต์‹ฌ ํŒ€์€ ํ•ด๋‹น ์„ค์ •์„ ์–ป๋Š” ๋ฐ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์†Œ์ผ“ ๊ฐ์ฒด๋ฅผ ์ „์†กํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ์žฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. :)

+1 IE11์€ _hasBinary์— '์Šคํƒ ๊ณต๊ฐ„ ๋ถ€์กฑ'์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

์ด ์˜ค๋ฅ˜๋Š” ์ „์ฒด ์†Œ์ผ“ ๊ฐœ์ฒด๋ฅผ ํด๋ผ์ด์–ธํŠธ๋กœ ๋‹ค์‹œ ๋ณด๋‚ด๋ ค๊ณ  ํ•  ๋•Œ ํ‘œ์‹œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ _์ •๋ง๋กœ_ ํ•„์š”ํ•œ ๊ฒƒ์€ socket.id ์˜€์œผ๋ฏ€๋กœ ๋” ์ž‘์€ ํ•ญ๋ชฉ์„ ๋‹ค์‹œ ๋ณด๋ƒˆ์„ ๋•Œ ์˜ค๋ฅ˜๊ฐ€ ์‚ฌ๋ผ์กŒ์Šต๋‹ˆ๋‹ค. ์ œ ๊ฒฝ์šฐ์—๋Š” ์ „์ฒด socket ๋Œ€์‹  socket.id ๋ฅผ ๋ณด๋ƒˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์Šคํƒ ํฌ๊ธฐ๋ฅผ ์ดˆ๊ณผํ•˜๋Š” ์žฌ๊ท€ ํ˜ธ์ถœ์„ ์ดˆ๋ž˜ํ•˜๋Š” ์ˆœํ™˜ ์ฐธ์กฐ๊ฐ€ ์žˆ๋Š” ๊ฐœ์ฒด๋ฅผ ๋ณด๋‚ด๋ ค๊ณ  ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ–ˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@LordMajestros ๊ทธ๊ฒƒ์€ ๋‚˜๋ฅผ ์œ„ํ•ด

@GerbenHofman ์ฒœ๋งŒ ์—์š”

NodeJS v4.4.4 ๋ฐ socket.io v1.4.5์—์„œ ๋™์ผํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

์ œ ๊ฒฝ์šฐ์—๋Š” ์—ฐ๊ฒฐ ํ•ด์ œ ์ด๋ฒคํŠธ ํ›„์— ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  socket.emit 20๋งŒ ๋ฒˆ ์ด์ƒ ํ˜ธ์ถœํ–ˆ์„ ๋•Œ๋งŒ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

socket.emit ํ˜ธ์ถœ ํšŸ์ˆ˜๊ฐ€ ์•ฝ 100,000๊ฐœ์ด๋ฉด ์ด ์˜ค๋ฅ˜๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

emit ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ํ•ญ์ƒ ๋ฌธ์ž์—ด์ž…๋‹ˆ๋‹ค.

์ด ์ •๋ณด๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?

@shunjikonishi ์— ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด ์ •ํ™•ํžˆ 100,000๊ฐœ์˜ ์ด๋ฒคํŠธ๋ฅผ ๋ณด๋‚ด์ž๋งˆ์ž ์ด๋Ÿฐ ์ผ์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” 1 ๊ฐœ์˜ ์–‘๋ง์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ 100,000์€ ํ•˜๋“œ ์บก์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ Node(๋˜๋Š” JavaScript ๋Ÿฐํƒ€์ž„)์— ์˜ํ•ด ๋ถ€๊ณผ๋œ ์ œํ•œ์ธ ๊ฒƒ ๊ฐ™์œผ๋ฉฐ Socket.io๋Š” ๋‹น์‹ ์ด ๋ฐฉ์ถœ์„ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ๋ฌด์–ธ๊ฐ€์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ๋ณด์œ ํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ 100,000๋ฒˆ์งธ ๋ฐฉ์ถœ์— ๋„๋‹ฌํ•˜๋ฉด ๊ทธ๋ƒฅ ๋„˜์–ด์ง‘๋‹ˆ๋‹ค.

Node 5.11.0 ๋ฐ Socketio 1.4.8์—์„œ ํ…Œ์ŠคํŠธ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด Node ๋ฒ„์ „์€ @shunjikonishi ์™€ ๋‹ค๋ฅด๋ฉฐ(๋‚ด ์šด์˜ ์ฒด์ œ ๋“ฑ, ์‹ค์ œ๋กœ ์ด 100,000์ด ์–ด๋””์—์„œ ์™”๋Š”์ง€ ์ „ํ˜€ ๋ชจ๋ฆ…๋‹ˆ๋‹ค) ์ด๊ฒƒ์ด ๋‚ด๊ฐ€ 100,000์—์„œ ์ œํ•œ์— ๋„๋‹ฌํ•œ ๋ฐ˜๋ฉด ๊ทธ๋Š” ์ตœ๋Œ€ 200,000์— ๋„๋‹ฌํ•œ ์ด์œ ๋ฅผ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ws.js๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋˜‘๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ–ˆ๊ณ  ์ž˜ ์ž‘๋™ํ–ˆ๊ณ  ๋ฌธ์ œ์—†์ด 100,000 ์†Œ์ผ“ ๋ฐฉ์ถœ์„ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์•„๋งˆ๋„ Socket.io์˜ ๋ฌธ์ œ ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์†Œ์ผ“ IO์—์„œ ์žฌ๊ท€ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐฉ์ถœ๋˜๊ณ  ์ด ์˜ค๋ฅ˜๋กœ ์ธํ•ด ์‹คํŒจํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋Š” ๋ณดํ˜ธ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ๊ฐ„๋‹จํ•œ ๊ฐ์ง€๋Š” ์ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ณ  ๋Œ€์‹  "์ˆœํ™˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋ ค๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค"์™€ ๊ฐ™์€ ์˜๋ฏธ ์žˆ๋Š” ์˜ค๋ฅ˜๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋””๋ฒ„๊น…์ด ๋” ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.

์ˆœํ™˜ ๋ฐ์ดํ„ฐ ๊ฐ์ง€๋ฅผ ์œ„ํ•œ ๋ช‡ ๊ฐ€์ง€ ๊ดœ์ฐฎ์€ ์†”๋ฃจ์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค. https://stackoverflow.com/questions/14962018/detecting-and-fixing-circular-references-in-javascript

ํ•œ ๊ฐ€์ง€ ๊ฐ„๋‹จํ•œ ์†”๋ฃจ์…˜์€ JSON.stringify๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ์ฐพ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

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

์ž์„ธํ•œ ๋‚ด์šฉ: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value

@adamreisnz PR ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค ;)

๋‚ด๊ฐ€ ๋Œ“๊ธ€์„ ๋‹ฌ๊ณ  5๊ฐœ์›” ํ›„์— ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๋‚˜๋ฅผ ๋ฉ˜์…˜ํ•˜๋ฉด ํ•ญ์ƒ ๋‹นํ™ฉ์Šค๋Ÿฌ์›Œ์š”๐Ÿ˜†

์ด ์˜ค๋ฅ˜๋„ ๋งŒ๋‚ฌ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•˜๋Š” ๋ฐ 2์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•ฉ๋‹ˆ๋‹ค.<.
A={B:{C:A}}์™€ ๊ฐ™์€ ์žฌ๊ท€ ๊ฐ์ฒด๋กœ ์ธํ•ด ๋ฐœ์ƒํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉฐ ๋ถ„๋ช…ํžˆ ์†Œ์ผ“ ์€ ์žฌ๊ท€ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค.
์‚ฌ์‹ค, buffer.js์—์„œ ๊ทธ๋“ค์ด ์žฌ๊ท€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณด๋‚ด๋ ค๋Š” ๋ฐ์ดํ„ฐ์˜ ๊ธธ์ด๋ฅผ ์ฐพ๊ธฐ ๋•Œ๋ฌธ์— ์ผ์–ด๋‚œ ์ผ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ "์ตœ๋Œ€ ํ˜ธ์ถœ ์Šคํƒ ํฌ๊ธฐ ์ดˆ๊ณผ"๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค. JSON.stringify()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ธธ์ด๋ฅผ ์–ป์œผ๋ฉด "์›ํ˜• ๊ตฌ์กฐ"์— ๋Œ€ํ•œ ๋˜ ๋‹ค๋ฅธ ๋ช…๋ฐฑํ•œ ์˜ค๋ฅ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฑด ๊ทธ๋ ‡๊ณ , ๊ทธ๊ฒƒ์€ ๊ตฌ๊ธ€์— ๋‚˜์œ ํ‚ค์›Œ๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค!

๋‚˜๋„ ๋ฐฉ๊ธˆ ์ด๊ฒƒ์— ๋ถ€๋”ช์ณค๋‹ค.

hasBin ๋Š” ์ˆœํ™˜ ์ฐธ์กฐ๊ฐ€ ์žˆ๋Š” ๊ฐœ์ฒด๋ฅผ ๋ณด๋‚ด๋ ค๊ณ  ํ•˜๋ฉด ์žฌ๊ท€ ๋ฃจํ”„๋กœ ์Šคํƒ์„ ์ฑ„์›๋‹ˆ๋‹ค.

์‰ฟ, ๋‚˜๋Š” โ€‹โ€‹์ด๊ฒƒ์„ ๊ณ ์น  2๋…„ ๋™์•ˆ ์—ด๋ฆฐ PR์ด ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•ˆ๋‹ค:

@dustingraham ์ˆ˜์ •์€

๋˜ํ•œ ๋” ์ด์ƒ hasBinary ๋ฉ”์„œ๋“œ๋ฅผ throwํ•˜์ง€ ์•Š๋”๋ผ๋„ ๋‚˜์ค‘์— ์ฝ”๋“œ์—์„œ ํ˜ธ์ถœ๋˜๋Š” 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 ๋“ฑ๊ธ‰