[번역] Socket.IO 는 어떻게 작동하는가?

여름노래불러줘·2022년 9월 12일
1

Socket.IO

목록 보기
1/5

의역 및 오역이 있을 수 있음.

어떻게 작동하는가

Socket.IO 서버 (Node.js) 와 Socket.IO 클라이언트 (브라우저, Node.js, 혹은 다른 언어들) 간 양방향 채널은 가능 할 때 WebSocket 연결로 설정되며, HTTP long-polling 을 fallback 으로 사용한다.

Socket.IO 코드베이스는 두 개의 레이어로 나눠져 있다.

  • 저레벨 파이프라인: Engine.IO 라고 부름. Socket.IO 내의 엔진
  • 높은 레벨 API: Socket.IO 자체

Engine.IO

Engine.IO 는 서버와 클라이언트간의 로우 레벨 연결 설립을 책임지고 있다.

소스 코드는 여기서 찾을 수 있음:

전송

현재 전송은 두 개가 구현되어 있다.

HTTP long-polling

HTTP long-polling 전송은 ("폴링" 이라고도 함) 연속적인 HTTP 전송으로 이루어진다.

  • 길게 실행되는 GET 요청은 서버로부터 데이터를 수신하기 위함
  • 짧게 실행되는 POST 요청은 서버로 데이터를 전송하기 위함

전송의 특성상, 연속적 emit은 연결 되어 동일한 HTTP 요청 내에서 전송될 수 있다(?).

웹소켓

WebSocket 전송은 서버와 클라이언트 사이에 양방향 및 저지연시간 통신 채널을 제공하는 WebSocket 연결로 구성된다.

전송의 특성상, 각 emit 은 각자 WebSocket 프레임으로 전송된다 (일부 emit 은 두 개의 WebSocket 프레임으로 나눠질 수도 있다. 더 많은 정보는 여기

핸드셰이크

Engine.IO 연결 시작 때 서버는 몇 개의 정보를 보낸다.

{
  "sid": "FSDjX-WRwSA4zTZMALqx",
  "upgrades": ["websocket"],
  "pingInterval": 25000,
  "pingTimeout": 20000
}
  • sid 는 세션의 ID 다. 모든 후속 HTTP 요청에는 반드시 sid 쿼리 파라미터가 포함되어야 한다.
  • upgrade배열은 서버에 의해 지원되는 "더 나은" 전송의 리스트를 담고 있다.
  • pingIntervalpingTimeout 값은 심박수 메커니즘에 사용된다.

업그레이드 메커니즘

기본 값으로, 클라이언트는 HTTP long-polling 전송으로 연결을 맺는다.

근데 왜?

WebSocket 은 분명히 양방향 통신을 맺는 가장 좋은 방법이나, 경험에 따르면 조직의 프록시 설정, 개인 방화벽 백신 소프트웨등에 의해 WebSocket 연결을 맺는게 항상 가능한 일은 아니다.

사용자의 관점에서 성공적이지 못한 WebSocket 연결은 실시간 애플리케이션이 데이터 교환을 시작하기까지 최대 10초를 기다려야 변환된다. 사용자 경험을 저해하는 것이다.

요악하면 Engine.IO 는 신뢰성과 사용자 경험을 우선으로 하며, 두 번째로 잠재적인 사용자 경험 개선과 서버 성능 향상에 중점을 둔다.

업그레이드 하기위해 클라이언트는

  • 나가는 버퍼가 비어있어야 한다.
  • 현재 전송을 읽기전용 모드로 변경한다.
  • 다른 전송으로 연결을 시도한다.
  • 성공하면, 처음 전송을 닫는다.

브라우저의 네트워크 모니터에서 확인할 수 있다.

  1. 핸드 셰이크 (zBjr...AAAK 세션 ID 포함 - 후속 요청에서 사용됨)
  2. 데이터 전송 (HTTP long-polling)
  3. 데이터 수신 (HTTP long-polling)
  4. 업그레이드(WebSocket)
  5. 데이터 수신 (4. 에서 WebSocket 연결이 성공적으로 맺어지면서, HTTP long-polling 닫힘)

연결 끊김 탐지

Engine.IO 연결이 닫힌 것으로 간주될 때

  • 하나의 HTTP 전송이(GET 이나 POST) 실패 (예를 들면, 서버가 다운됨)
  • WebSocket 연결이 닫힘 (예를 들면, 사용자가 브라우저의 탭을 닫았을 때)
  • 서버나 클라이언트 사이드에서 socket.disconnect() 가 호출 되었을 때

서버와 클라이언트가 아직 살아있고 작동 중인지 확인하는 심박수 메커니즘도 있다.
주어진 인터벌 (핸드 셰이크시 보내진 pingInterval 값)에 서버가 PING 패킷을 전송하고, 클라이언트가 PONG 패킷을 돌려 보낼 몇 초의 시간이 있다 (pingTImeout 값) 서버가 PONG 패킷을 수신 받지 못하면 연결이 닫힌 것으로 간주한다. 반대로, 클라이언트가 PING 패킷을 pingInterval + pingTimeout내에 수신하지 못해도 연결이 닫힌 것으로 간주한다.

연결이 끊기는 이유는 여기(서버 사이드) 와 여기 (클라이언트 사이드)

Socket.IO

Socket.IO 는 Engine.IO 위에서 몇 가지 추가 기능을 제공한다.

소스코드는 여기서 찾을 수 있다.

0개의 댓글