socket.io에서 하트비트(heartbeat) 설정하기

socket.io를 사용하면서 클라이언트 연결상태 확인을 위해 connect/disconnect 체크가 필요했습니다.

네트워크가 끊여지면 disconnect 이벤트가 와야하는데 disconnect 이벤트 응답이 네트워크가 끊어진 시간보다

꽤 늦게 도착하여 처리에 문제가 있었고, 원인을 분석하다보니 연결상태 확인을 위한 heartbeat 때문이었습니다.


socket.io에 대해서 정확히 알지는 못하지만 알고있는 범위내에서 설명을 드리면..


socket.io에서 heartbeat 관련하여 설정하는 것이 heartbeat timeoutheartbeat interval 2가지 있습니다. 

두 설정값에 대한 설명을 공식문서에는 못찾았고, stackoverflow에서 찾았습니다.


As far as I can tell, there are 2 values that matter here: the server sends heartbeats to the client every heartbeat interval seconds; the client responds directly, if there is no response, the server decides the client is dead. The client waits for a heartbeat from the server for heartbeat timeout seconds since the last heartbeat (which should obviously be higher than the heartbeat interval). If it hasn't received word from the server in heartbeat timeout seconds, it assumes the server is dead (and will start disconnecting / reconnecting based on the other options you have set. 


 Default values are heartbeat interval = 25s and heartbeat timeout = 60s. Both items are set on the server, the heartbeat timeout is sent to the client upon connecting.

아주 짧은 영어로 살짝 보면(제대로 이해했는지는 모르겠지만..ㅠ), 

서버는 heartbeat interval 초 간격으로 클라이언트에게 heartbeat를 전송하고 클라이언트가 응답하지 않으면 서버는 클라이언트가 죽은 것으로 판단합니다.

클라이언트는 마지막 heartbeat를 전송받고 heartbeat timeout 시간동안 서버로부터 heartbeat가 오기를 기다립니다. heartbeat timeout 시간 동안 서버로부터 heartbeat를 전송받지 못하면 서버가 죽은 것으로 판단하고 접속종료와 재접속 흐름을 진행합니다. 기본값으로 heartbeat interval은 25초, heartbeat timeout은 60초로 설정되어 있습니다.


heartbeat interval과 heartbeat timeout 설정은 아래 처럼 하면 됩니다. 단위는 밀리초(ms) 입니다.

io.set('heartbeat timeout', 15000);
io.set('heartbeat interval', 8000);

이렇게 설정하는 방식은 아마도 0.9 버전 이전까지 사용했던 방식으로 보입니다.

1.0 버전부터는 다른 방법으로 설정하며 하위 호환성을 위해 기존 방식도 사용할 수 있습니다.

var server = app.listen(80);
io = socketio(server,{'pingInterval': 45000});

그리고 1.0 버전 부터는 heartbeat timeout 의 이름이 pingTimeout으로, heartbeat interval이 pingInterval로 이름이 변경되었지만 하위 버전 호환을 위해 기존 이름도 사용할 수 있습니다. 

socket.io 쪽 코드를 살펴보면 아래와 같은 코드가 있습니다.

/**
 * Old settings for backwards compatibility
 */

var oldSettings = {
  "transports": "transports",
  "heartbeat timeout": "pingTimeout",
  "heartbeat interval": "pingInterval",
  "destroy buffer size": "maxHttpBufferSize"
};

socket.io 쪽 코드를 보면 default 값이 지정되는 부분도 있습니다.

/**
 * Server constructor.
 *
 * @param {Object} options
 * @api public
 */

function Server(opts){
  if (!(this instanceof Server)) {
    return new Server(opts);
  }

  this.clients = {};
  this.clientsCount = 0;

  opts = opts || {};
  this.pingTimeout = opts.pingTimeout || 60000;
  this.pingInterval = opts.pingInterval || 25000;
  this.upgradeTimeout = opts.upgradeTimeout || 10000;
  this.maxHttpBufferSize = opts.maxHttpBufferSize || 10E7;
  this.transports = opts.transports || Object.keys(transports);
  this.allowUpgrades = false !== opts.allowUpgrades;
  this.allowRequest = opts.allowRequest;
  this.cookie = false !== opts.cookie ? (opts.cookie || 'io') : false;

  // initialize websocket server
  if (~this.transports.indexOf('websocket')) {
    this.ws = new WebSocketServer({ noServer: true, clientTracking: false });
  }
}

socket.io는 아주 조금씩만 보고 있는 상태이기에 잘못된 내용이나 더 좋은 해결방법이 있을 수 있습니다.

잘못된 부분이나 더 좋은 방법을 알려주세요ㅠ