Socket.IO

QT-HH·2022년 2월 17일
0

JavaScript

목록 보기
3/5

Socket.IO

브라우저와 서버간의 실시간 event-based 양방향 커뮤니케이션
이 문서에서는 client만 다룹니다.

ClientWebSocket프로토콜 연결이 가능한 경우 연결하고, 아니면 HTTP long polling으로 폴링한다.

가벼운 예제

// WebSocket API
const socket = new WebSocket("ws://localhost:3000");

socket.onopen = () => {
  socket.send("Hello!");
};

socket.onmessage = (data) => {
  console.log(data);
};
// Socket.IO
const socket = io("ws://localhost:3000");

socket.on("connect", () => {
  // either with send()
  socket.send("Hello!");

  // or with emit() and custom event names
  socket.emit("salutations", "Hello!", { "mr": "john" }, Uint8Array.from([1, 2, 3, 4]));
});

// handle the event sent with socket.send()
socket.on("message", data => {
  console.log(data);
});

// handle the event sent with socket.emit()
socket.on("greetings", (elem1, elem2, elem3) => {
  console.log(elem1, elem2, elem3);
});

Caution

  • Socket.IOWebSocket을 상속받은 것이 아니다.
    • Socket.IO는 각 패킷에 추가적인 metadata를 넣는다.
    • WebSocket 클라이언트는 Socket.IO서버에 접속하지 못하고,
      Socket.IO클라이언트는 WebSocket서버에 접속하지 못한다.
  • Socket.IO는 모바일 전용 서비스에서는 사용하면 안된다.
    • 서버와 TCP연결을 하는데 이것은 유저의 배터리를 빠르게 소모한다.

특징

  • WebSocket연결을 할 수 없을 때는 HTTP long-polling을 이용하기 때문에 연결에 대한 신뢰성이 있다.
  • 자동 재연결
  • 패킷 버퍼링
  • Acknowledgements (커스텀 이벤트)
  • 브로드캐스팅 to 모든 클라이언트, 클라이언트의 subset들
  • 네임스페이스에 따른 engine options 공유


Engine.IO

서버-클라이언트간 low-level 연결을 책임진다.

  • 연결과 메커니즘 upgrade(프로토콜 전환)

  • disconnection 탐지

  • 구조

    • ManagerSocket들의 reconnect 로직을 관리한다.
    • 각각의 Socket은 같은 Manager 인스턴스를 사용할 수도 있고, 모두 따로 사용할 수도 있다. (forceNew, multiplex 옵션, Namespaces)
    • 같은 Manager인스턴스를 공유하는 Socket들은 engine options, 패킷 버퍼를 공유한다. (하나의 연결에 의존)

Transports

두 가지의 연결이 있다.

  • HTTP long-polling
    • long-running GET requests (동일한 클라이언트가 서비스 반복요청)
    • short-running POST requests (서버-클라이언트간 단 하나의 상호작용 (요청-응답))
    • 연속적인 emit은 동일한 http요청 내에서 연결되고 전송될 수 있다.
  • WebSocket 연결
    • JS의 Websocket 인터페이스를 쓰지않는다.
    • ws / wss 프로토콜을 사용하여 통신
    • emit은 자체 웹소켓 프레임으로 전송

HandShake

Engine.IO 연결이 시작될 때, 서버에서 다음과 같은 정보를 보낸다.

{
  "sid": "FSDjX-WRwSA4zTZMALqx",
  "upgrades": ["websocket"],
  "pingInterval": 25000,
  "pingTimeout": 20000
}
  • sid는 session ID이고, 이후 모든 HTTP요청의 쿼리파라미터에 포함되어야 한다.
  • upgrades에는 서버에 의해 지원되는 더 나은 방식의 전송 리스트가 포함되어있다.
  • pingIntervalpintTimeout은 주기적인 신호 메커니즘에 사용된다.
    • pingInterval: 서버가 ping패킷을 보내는 주기
    • pingTimeout: 클라이언트가 ping패킷을 받고나서 pong패킷을 보내기까지의 시간

Upgrade mechanism

HTTP long-polling이 전송의 기본값이다.
Engine.IO는 서버의 퍼포먼스보단 유저경험의 관점에서 더 나은 방법을 선택했다.
연결이 안 될 수도 있는 WebSocket이 아닌 HTTP long-polling을 default로 설정해서 연결의 신뢰성을 취한다.

Disconnection detection

다음 상황에서 Engine.IO는 연결이 끊어졌음을 인식한다.

  • HTTP request fail
  • WebSocket 연결이 닫혔을 때
  • socket.disconnect()함수가 호출됐을 때 (서버 혹은 클라이언트에서)
  • 서버에서 pong패킷을 받지 못했거나 클라이언트에서 ping패킷을 받지 못했을 때


장단점

장점

  • WebSocket 통신이 안돼도 HTTP long-polling 통신을 통해 신뢰성있는 실시간에 가까운 연결을 할 수 있다.
  • Acknowledgements를 통해 custom event emit을 할 수 있다.

단점

  • JavaScript에서 지원하는 WebSocket객체로 만든 서버를 사용하지 못한다
  • 서버도 똑같이 Socket.IO를 이용해서 만들어야한다.


참고

profile
FE 초짜

0개의 댓글