이전 학습에서 Socket.IO퍼블릭/브로드캐스트/프라이빗 전송 개념에 대해 알아보았습니다. 프라이빗 전송을 이용하면 특정 대상에게만 패킷을 소비할 수 있다는 사실을 알 수 있었죠. 이를 응용하여 이 번 시간에는 효율적으로 패킷을 소비할 수 있는 방법에 대하여 알아보겠습니다.

근대 웹 사용 행태에서 두드러진 변화중 하나는 탭 브라우징입니다. 이로 인해 사용자들이 사이트에 머물러있는 시간도 급격히 늘어나게 되었습니다. 이는 곧 웹사이트에 접속되어 있는 상태이긴 하지만 사용자가 웹사이트를 이용중이지 않을 수도 있다는 것을 의미합니다. 혹은 페이지가 열여있는 상태지만 다른 창에서 작업중인 경우도 마찬가지죠. 무조건 온라인 상태의 사용자를 통신 대상으로 삼는 Socket.IO는 무의미한 패킷을 소비하는 상태일수도 있다는 것입니다. 아쉽게도 이를 우회하는 장치를 제공하고 있지 않기 때문에 직접 구현해야 합니다.

아래는 이전 학습에 사용했던 코드에 추가적으로 idle(유휴) 상태를 구분할수 있도록 추가하고 유효한 상태의 클라이언트들에게만 패킷을 소비하도록 하는 내용을 작성한 것입니다.

 var io = require('socket.io').listen(8080);

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

  var timeout = 10000 // idle timeout
    , sockets = io.sockets.sockets // sockets store
    , clients = {} // clients store
    , timer = null; // timeout store

  idle();

  socket.on('join', function (data) {
    clients[socket.id] = {
      idle: false
    };
    socket.broadcast.emit('join', socket.id, data);
  });

  socket.on('message', function (data) {
    for (var id in clients) {
      if (socket.id != id && !clients[id].idle)
        sockets[id].emit('message', socket.id, data);
    }
    idle();
  });

  socket.on('whisper', function (id, data, fn) {
    if (id && sockets[id]) {
      sockets[id].emit('whisper', socket.id, data);
      fn(true);
    } else {
      fn(false);
    }
    idle();
  });

  socket.on('idle', function (data) {
    clients[socket.id].idle = data; // boolean
    socket.broadcast.emit('idle', socket.id, data);   
  });

  socket.on('disconnect', function () {
    clear();
    delete clients[socket.id];
    socket.broadcast.emit('close', socket.id);
  });

  // set idle timer
  function idle() {
    clear();
    timer = setTimeout(function() {
      if (clients[socket.id]) {
        clients[socket.id].idle = true;
        socket.broadcast.emit('idle', socket.id, true);
      }
      timer = null;
    }, timeout);
  }

  // clear idle timer
  function clear() {
    clients[socket.id].idle = false;
    timer && clearTimeout(timer);
  }

});

이것으로 대상이 자리를 비웠는지를 서버가 감시할 수 있게 되었으며, 자리를 비운 사용자에게는 패킷을 절약할 수 있습니다. 이와 유사한 로직을 클라이언트-사이드에 추가하여 사용자들의 상태를 공유하는 기능을 추가하고 사용자에게 알릴수 있습니다. 마우스 움직임이나 클릭을 감시하여 유휴상태를 측정하는 코드를 작성하면 더욱 신용할 수 있는 유휴상태 구분할 수 있게됩니다. 하지만, 채팅과 같은 기록성 패킷이나 알림성 패킷인 'join'이나 'disconnect'에는 적용하지 않는것이 좋겠죠?

Comments

Got something to add? You can just leave a comment.

Your Reaction Time!

avatar

captcha