간결하게 알아보는 웹소켓 vs 소켓io (WebSocket VS Socket.IO)

김동준·2024년 10월 8일
3

면접 뿌셔뿌셔

목록 보기
1/5
post-thumbnail

결론

정의

웹소켓: 클라이언트와 서버가 양방향 실시간 통신할 수 있게 하는 프로토콜(규약)입니다.
소켓: 웹소켓을 포함한 라이브러리로, 웹소켓에서 직접 구현해야 할 추가기능들을 포함하고 있습니다.

차이

웹소켓은 소켓에 비해, 1. 매우 빠르고 2. 통신을 위해 아주 적은 데이터만을 이용 3. 비교적 구현이 어려우나(모두 직접 구현), 구현이 자유롭습니다.
소켓은 웹소켓에 비해, 1. 느리고 2. 많은 데이터를 사용하나 3. 라이브러리이므로 기능 구현이 간편합니다. 4. 보다 보안이 우수하고, 안정적입니다. (고수들이 미리 만들어놓았으므로)
예를 들자면, 웹소켓은 집에서 직접 해먹는 음식이고 소켓.IO는 레스토랑에서 먹는 음식입니다. 가격 차이, 만들어야하는 수고로움, 퀄리티의 차이의 면에서 그렇습니다.

웹소켓이란?

왜 필요할까?

HTTP 통신
출처: 골든래빗 - 웹소켓과 소켓io

웹은 HTTP 프로토콜 위에서 동작하기 때문에, 클라이언트가 요청을 보내야만 서버가 응답을 보냅니다. 즉, 양방향 통신을 지원하지 않습니다.
웹소켓 전에는, 몇 초에 한번씩 서버가 알아서 응답해주려면 클라이언트가 서버에 주기적으로 의미없는 요청을 보내야 했습니다. (폴링 방식과 롱폴링 방식이 있습니다.)

폴링: 주기적으로 요청을 보내는 방식

웹소켓

화면 갱신없이, 실시간성을 요구하는 애플리케이션을 만들고자 양방향 통신 방식인 웹소켓 프로토콜(규약, 약속)이 나왔습니다.
아래와 같이 브라우저 상에서 리프레시(화면 갱신)없이 실시간성을 요구하는 애플리케이션을 구현할 수 있게 된 것입니다.

특징

장점
1. 매우 빠르고 통신할 때 아주 적은 데이터만 이용
2. HTML5 웹 표준 기술(프로토콜)로, 대다수 브라우저에서 기본적으로 지원하기 때문에 매우 가벼움. 구현이 자유롭다. Low-Level 단계의 통신 방식입니다.
3. 이벤트를 단순히 듣고(Listening) 보내는 것(emit)만 가능함
단점
1. 구현이 어려움(직접 아키텍처를 설계해야 하고, 재연결, 룸, 구독 등 기능을 모두 구현해야함)
2. 예전 방식이라 업데이트가 없음.
3. 작동하지 않는 환경과 제한 사항에 대한 이해가 필요함 (웹소켓 브라우저 호환성
예시 - 실시간 채팅, 주식 앱 등

웹소켓은 데이터를 전송하는 것만 지원할 뿐, 전송되는 데이터로 채팅방을 만들거나 메시지 발송하기를 만드는 등의 기능 추가는 모두 개발자의 몫입니다.

작동 원리


1. 서버와 클라이언트가 최초 한번 커넥션을 맺습니다.(핸드쉐이크 과정)
2. 커넥션이 연결되면, 클라이언트는 서버로 데이터(Message, 프레임(Frame)의 모음, 바이트의 배열)을 보냅니다.
3. 3단계에서 접속을 끊습니다.

프레임구조(출처)

구현 코드

출처: Node WebSocket vs Socket.IO

npm에서 설치
npm i -g websocket-vs-socket.io

Express.js를 활용한 WebSocket server 예제

// ServerSide
var path = require('path');
var app = require('express')();
var ws = require('express-ws')(app);
app.get('/', (req, res) => {
  console.error('express connection');
  res.sendFile(path.join(__dirname, 'ws.html'));
});
app.ws('/', (s, req) => {
  console.error('websocket connection');
  for (var t = 0; t < 3; t++)
    setTimeout(() => s.send('message from server', ()=>{}), 1000*t);
});
app.listen(3001, () => console.error('listening on http://localhost:3001/'));
console.error('websocket example');

WebSocket Client (Vanilla JavaScript)

var l = document.getElementById('l');
var log = function (m) {
    var i = document.createElement('li');
    i.innerText = new Date().toISOString()+' '+m;
    l.appendChild(i);
}
log('opening websocket connection');
var s = new WebSocket('ws://'+window.location.host+'/');
s.addEventListener('error', function (m) { log("error"); });
s.addEventListener('open', function (m) { log("websocket connection open"); });
s.addEventListener('message', function (m) { log(m.data); });

소켓IO란?

Socket.IO는 Node.js 기반의 서버-클라이언트의 웹소켓 양방향 통신을 지원하는 라이브러리입니다. 기본적으로 웹소켓을 지원하며 웹소켓을 지원하지 않는 브라우저에서는 롱폴링 방식을 사용한 통신을 지원합니다. 또한, 재접속, 브로드캐스팅, 멀티플렉싱 기능도 제공합니다.

자동 연결기능: 소켓 연결 실패시 fallback을 통해 알아서 해당 클라이언트와 연결을 시도합니다.
브로드캐스팅: 접속한 클라이언트 모두에게 메시지를 전송하는 것을 의미
멀티플렉싱: 커넥션 하나를 논리적으로 나누어서 데이터를 원하는 채널에만 전송하는 기법. 게임의 채널의 개념과 비슷하다. 네임스페이스라고 부르며, 채팅방을 만드는 기능인 룸(Room)으로 채팅방별로 메시지를 통신하는 정교한 메시지 송수신 제어 가능

특징

장점
1. 더 많은 브라우저를 지원하고, 더 많은 기능을 제공하지만 오버헤드도 따름(참고)
2. 보안성 측면에서 더 우수합니다.
3. Ajax 롱 폴링을 비활성하면, websocket 연결처럼 사용 가능(선택 가능함)
4. 룸, 구독 서비스 등 기능이 있음. 고로 구현이 쉽다.
5. 라이브러리기 때문에 커뮤니티가 활성화되어 있음.
단점
1. 웹 소켓에 비해 더 느림. 데이터 사용이 많음(기본적으로 180kb의 추가 메타데이터, 성능비교(페이지 하단부))
예시 - 연결된 소켓(클라이언트)들을 세밀하게 관리해야 하는 서비스인 경우에 유지보수 측면에서 좋음.

주의. Socket.IO는 WebSocket을 사용하지만, 각 데이터 패킷에 추가하는 방식입니다. 그래서 websocket 클라이언트는 socket.io 서버에 연결할 수 없으며, socket.io 클라이언트는 websocket 서버에 연결할 수 없습니다.

구현 코드

Socket.IO Server (Express.js)

var path = require('path');
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', (req, res) => {
  console.error('express connection');
  res.sendFile(path.join(__dirname, 'si.html'));
});
io.on('connection', s => {
  console.error('socket.io connection');
  for (var t = 0; t < 3; t++)
    setTimeout(() => s.emit('message', 'message from server'), 1000*t);
});
http.listen(3002, () => console.error('listening on http://localhost:3002/'));
console.error('socket.io example');

Socket.IO Client (vanilla js)

var l = document.getElementById('l');
var log = function (m) {
    var i = document.createElement('li');
    i.innerText = new Date().toISOString()+' '+m;
    l.appendChild(i);
}
log('opening socket.io connection');
var s = io();
s.on('connect_error', function (m) { log("error"); });
s.on('connect', function (m) { log("socket.io connection open"); });
s.on('message', function (m) { log(m); });

Dalseo 님의 Sokcet.io 코드

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <title>Socket.IO chat</title>
  <link
    rel="stylesheet"
    href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"
  />
  <style>
    main { display: flex; flex-direction: column; height: 100dvh; }
    article { flex-grow: 1; }
  </style>
  <script type="module">
    import { io } from "https://cdn.socket.io/4.7.5/socket.io.esm.min.js";
    const socket = io();
    const ul = document.querySelector('ul');
    socket.on('message', (msg) => {
      const li = document.createElement('li');
      li.textContent = msg;
      ul.appendChild(li);
      window.scrollTo(0, document.body.scrollHeight);
    });
    const form = document.querySelector('form');
    const input = document.querySelector('input');
    form.addEventListener('submit', (event) => {
      event.preventDefault();
      if (input.value) {
        socket.emit('message', input.value);
        input.value = '';
      }
    });
  </script>
</head>

자료 출처:
Socket.io 공식 페이지
Differences between socket.io and websockets
Goldenrabbit님의 웹소켓과 socket.io

profile
고민하고 고뇌하는 개발자 (점심, 저녁 메뉴를)

0개의 댓글