[번역] Socket.IO 에 대하여

여름노래불러줘·2022년 9월 11일
0

Socket.IO

목록 보기
2/5

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

Socket.IO란 무엇인가

Socket.IO 는 서버와 클라이언트가 저지연시간, 양방향이벤트 기반 통신을 가능케 하는 라이브러리이다.

WebSocket 프로토콜 위에 구축되었으며, HTTP 롱 폴링으로의 fallback 이나 자동 재연결 같은 추가적인 보증을 제공한다.

> INFO
WebSocket 은 서버와 브라우저간 전이중 통신과 저지연시간 채널을 제공하는 통신 프로토콜이다.
더 많은 정보는 여기서 찾을 수 있다.

이용 가능한 Socket.IO 서버 구현:

그리고 주로 사용하는 언어들의 클라이언트 구현:

WebSocket을 사용한 기본 예제:

서버 (ws 기반)

import { WebSocketServer } from "ws";

const server = new WebSocketServer({ port: 3000 });

server.on("connection", (socket) => {
  // send a message to the client
  socket.send(JSON.stringify({
    type: "hello from server",
    content: [ 1, "2" ]
  }));

  // receive a message from the client
  socket.on("message", (data) => {
    const packet = JSON.parse(data);

    switch (packet.type) {
      case "hello from client":
        // ...
        break;
    }
  });
});

클라이언트

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

socket.addEventListener("open", () => {
  // send a message to the server
  socket.send(JSON.stringify({
    type: "hello from client",
    content: [ 3, "4" ]
  }));
});

// receive a message from the server
socket.addEventListener("message", ({ data }) => {
  const packet = JSON.parse(data);

  switch (packet.type) {
    case "hello from server":
      // ...
      break;
  }
});

Socket.IO 의 같은 예제:

서버

import { Server } from "socket.io";

const io = new Server(3000);

io.on("connection", (socket) => {
  // send a message to the client
  socket.emit("hello from server", 1, "2", { 3: Buffer.from([4]) });

  // receive a message from the client
  socket.on("hello from client", (...args) => {
    // ...
  });
});

클라이언트

import { io } from "socket.io-client";

const socket = io("ws://localhost:3000");

// send a message to the server
socket.emit("hello from client", 5, "6", { 7: Uint8Array.from([8]) });

// receive a message from the server
socket.on("hello from server", (...args) => {
  // ...
});

두 예제는 매우 비슷하게 보이지만 Socket.IO 는 WebSocket 기반으로 작동중인 애플리케이션의 복잡성을 은밀히 숨기는 기능을 제공한다. 이런 기능들은 아래에 리스트 되어있다.

Socket.IO 가 아닌 것

그런데 먼저 Socket.IO 가 아닌 것 부터 확실히 해두자.

> 주의
Socket.IO 는 웹소켓 구현이 아니다.

비록 Socket.IO 가 전송을 위해 가능하면 WebSocket 을 사용하나, 각 패킷에 메타데이터를 추가한다. 이것이 WebSocket 클라이언트가 Socket.IO 서버에 성공적으로 연결할 수 없는 이유이다. Socket.IO 클라이언트도 마찬가지로 보통 WebSocket 서버에 연결할 수 없다.

// 경고: 클라이언트는 연결되지 않을 것!
const socket = io("ws://echo.websocket.org");

WebSocket 서버를 찾고 있다면 wsμWebSocket.js를 참조

Node.js 의 코어에 WebSocket 서버를 포함시킬 것인지에 대한 토론도 있다.

클라이언트 사이드라면 robust-websocket 패키지에도 흥미가 생길 수 있다.

> 주의
Socket.IO 는 모바일 애플리케이션의 백그라운드 서비스에 사용하는 것이 아니다.

Socket.IO 라이브러리는 서버로의 TCP 연결을 계속 열어둔다. 사용자의 배터리를 많이 소비하는 결과로 이어질 수 있다. 이 경우엔 FCM 같은 전용 메시징 플랫폼을 이용하길 바람.

기능

WebSocket 을 통해 Socket.IO 에 의해 제공되는 기능들

HTTP long-polling fallback

WebSocket 연결이 맺어지지 않는 경우 연결이 HTTP long-polling 으로 하위호환 될 수 있다.
이 기능은 생성된지 10년이 넘은(!) 프로젝트에 Socket.IO 를 사용하는 이유 #1 이었다. 당시에는 WebSocket 에 대한 브라우저 지원이 초기단계 였기 때문이다.

현재는 대부분의 브라우저에서 WebSocket 을 지원하더라도 (97% 이상), 잘못 구성된 프록시 때문에 WebSocket 연결이 맺어질 수 없었다는 보고를 사용자로부터 받기 때문에 아직도 대단한 기능이다.

Automatic reconnection

특정한 조건에서 서버와 클라이언트간 WebSocket 연결은 양쪽이 링크의 끊어진 상태를 인식하지 못하는 상태에서 중단될 수 있다.

그래서 Socket.IO는 주기적으로 연결 상태를 확인하는 심박수 메커니즘을 포함하고 있다.

그리고, 결국 클라이언트가 연결이 끊어졌을 때 서버가 먹통이 되지 않기 위해 exponential back-off delay 로 자동으로 다시 연결한다.

Packet buffering

클라이언트 연결이 끊어졌을 때 패킷은 자동으로 버퍼링 되어 있다. 그리고 다시 연결 되었을 때 전송될 것이다.

여기서 더 많은 정보 보기

Acknowledgements

Socket.IO 는 이벤트를 전송하고 응답을 수신하는데 편리한 방법을 제공한다.

송신자

socket.emit("hello", "world", (response) => {
  console.log(response); // "got it"
});

수신자

socket.on("hello", (arg, callback) => {
  console.log(arg); // "world"
  callback("got it");
});

타임아웃도 추가할 수 있다.

socket.timeout(5000).emit("hello", "world", (err, response) => {
  if (err) {
    // 다른 한 쪽이 딜레이 내에 이벤트를 알아차리지 못함.
  } else {
    console.log(response); // "got it"
  }
});

Broadcasting

서버 사이드에서 연결된 모든 클라이언트클라이언트의 부분집합에게 이벤트를 전송할 수 있다.

// to all connected clients
io.emit("hello");

// to all connected clients in the "news" room
io.to("news").emit("hello");

다수의 노드로 스케일링(규모를 확장하거나 축소)해도 작동함.

Multiplexing

네임스페이스는 단일 공유 연결을 통해 애플리케이션의 로직을 분할시킬 수 있다. 예를 들면 인가된 사용자만 입장할 수 있는 "admin" 채널을 생성하는데 유용하다.

io.on("connection", (socket) => {
  // classic users
});

io.of("/admin").on("connection", (socket) => {
  // admin users
});

그 이상은 여기서.

Common questions

Socket.IO 가 오늘날에도 필요한가?

웹소켓이 거의 모든 곳에서 지원되기 시작한 현재, 합당한 질문이다.

그 말은 애플리케이션을 위해 WebSocket 만 사용하겠다면 reconnection, acknowledgements, broadcasting 처럼 Socket.IO 에 이미 포함된 대부분의 기능들을 결국 구현해야 한다 (실전 테스트도 된).

Socket.IO 프로토콜의 오버헤드는 무엇인가?

socket.emit("hello", "world")42["hello","world"] 를 포함하는 단일 WebSocket 프레임으로 전송 될 것이다.

  • 4 는 Engine.IO "메시지" 패킷 타입이다.
  • 2 는 Socket.IO "메시지" 패킷 타입이다.
  • ["hello","world"]JSON.stringfy() 된 아규먼트 배열이다.

따라서 각 메시지에 대해 몇 추가 바이트가 필요하며, 이는 커스텀 파서를 사용해 더 줄일 수 있다.

> INFO
브라우저 번들 자체의 사이즈는 10.4kB 이다. (minified and gzipped)

뭔가 잘 안되서 도움이 필요하면?

트러블 슈팅 가이드 확인

다음 스텝

0개의 댓글