C
네트워크/실시간/Lesson 08

실시간 통신 — WebSocket · SSE · Long Polling

30분·theory

실시간 통신 — WebSocket · SSE · Long Polling

🎯 이 lesson 을 읽고 나면

이 lesson 을 다 읽고 나면 아래 3가지를 자신 있게 할 수 있습니다.

  • ✅ WebSocket vs SSE vs Long Polling 차이
  • ✅ socket.io 의 fallback 메커니즘
  • ✅ WebRTC 의 P2P 연결 + STUN/TURN

학습 목표를 체크리스트로 두고 다 답할 수 있게 되면 lesson 을 닫으세요.

실시간 통신 4 방식 비교

실시간 = 서버 → 클라이언트 푸시 (또는 양방향).

방식방향프로토콜용도
Polling클라이언트 pullHTTP가벼운 폴링 (예: 5초마다)
Long Pollingpull (긴 대기)HTTP채팅·알림 (이벤트까지 대기)
SSE서버 → 클라이언트HTTP알림·라이브 피드 (단방향)
WebSocket양방향WS/WSS채팅·게임·실시간 협업
gRPC streaming양방향HTTP/2내부 MSA
WebRTCP2PUDP화상·오디오

선택 가이드:

  • 🟢 단방향 알림 → SSE (간단·자동 재연결)
  • 🟢 양방향 채팅·게임 → WebSocket
  • 🟢 P2P 화상 → WebRTC
  • 🟢 폴링 + 호환성 → Long Polling (구형 브라우저)
  • 🔴 단순 폴링 → 가급적 피하기

WebSocket 동작 + 사용 패턴

WebSocket = 한 TCP 연결로 양방향 메시지:

Handshake (HTTP → WS 업그레이드):

code
GET /ws HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: <base64>
Sec-WebSocket-Version: 13

응답:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Sec-WebSocket-Accept: <hash>

클라이언트 (브라우저):

javascript
const ws = new WebSocket('wss://example.com/ws');

ws.onopen = () => ws.send(JSON.stringify({ type: 'subscribe', room: 'general' }));
ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  console.log(msg);
};
ws.onerror = (e) => console.error(e);
ws.onclose = () => console.log('연결 종료');

서버 (Node.js + ws):

javascript
const { WebSocketServer } = require('ws');
const wss = new WebSocketServer({ port: 8080 });

wss.on('connection', (ws) => {
  ws.on('message', (data) => {
    const msg = JSON.parse(data);
    if (msg.type === 'chat') {
      // 브로드캐스트
      wss.clients.forEach(c => {
        if (c.readyState === WebSocket.OPEN) {
          c.send(JSON.stringify({ user: msg.user, text: msg.text }));
        }
      });
    }
  });
});

실무 라이브러리:

  • Socket.IO — fallback (XHR·Long polling), 룸·네임스페이스
  • Pusher·Ably·Supabase Realtime — 관리형
  • Centrifugo·Mercure — 셀프 호스팅

확장 패턴:

  • Redis Pub/Sub — 여러 서버 간 메시지 라우팅
  • Sticky session — 같은 사용자는 같은 서버 (또는 Redis 로 상태 공유)
  • 하트비트 (ping/pong) — 끊긴 연결 감지 (보통 30초)

SSE + Long Polling

SSE (Server-Sent Events)서버 → 클라이언트 단방향 스트림:

클라이언트 (브라우저):

javascript
const es = new EventSource('/api/notifications');
es.onmessage = (event) => {
  const data = JSON.parse(event.data);
  showNotification(data);
};
es.onerror = () => console.log('재연결 중...');     // 자동 재연결
es.close();    // 종료

서버 (Node.js):

javascript
app.get('/api/notifications', (req, res) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');

  const interval = setInterval(() => {
    res.write(`data: ${JSON.stringify({ msg: 'hi', time: Date.now() })}

`);
  }, 1000);

  req.on('close', () => clearInterval(interval));
});

SSE 장점:

  • HTTP 표준 (방화벽·프록시 친화)
  • 자동 재연결
  • WebSocket 보다 단순
  • Last-Event-ID 헤더로 끊긴 시점부터 재개

SSE 단점:

  • 단방향만 (클라이언트 → 서버는 별도 POST)
  • IE 미지원 (이제 무시 가능)
  • HTTP/1.1 동시 연결 제한 (HTTP/2 이상 권장)

Long Polling — 응답을 최대한 늦게:

code
1. 클라이언트: GET /poll?last=42
2. 서버: 새 이벤트 있을 때까지 *응답 보류* (최대 30초)
3. 새 이벤트 → 즉시 응답
4. 또는 30초 타임아웃 → 빈 응답
5. 클라이언트: 즉시 다시 폴링 (1로)

용도:

  • 구형 브라우저 (IE9-)
  • WebSocket·SSE 차단 환경
  • 단순 알림 (1초 이내 지연 허용)

대부분 → WebSocket·SSE 가 더 효율

🤖 AI 에게 이렇게 요청해보세요

이 lesson 의 개념을 알면 AI 에게 구체적으로 지시할 수 있습니다. 막연한 "고쳐줘" 가 아니라 어휘를 가진 요청 — 그게 토큰 절약의 출발점입니다.

  • "이 polling 코드를 WebSocket (socket.io) 으로 마이그레이션해줘"
  • "이 SSE 를 WebSocket vs SSE 비교 후 적합한 쪽으로 정리해줘"

왜 이게 토큰을 줄이나

개념을 모를 땐 AI 답변을 받고도 "그게 뭐예요?" 를 다시 물어야 합니다. 그 "다시 물음" 이 토큰을 잡아먹습니다. 개념 한 번 익혀두면 대화가 한 번에 끝납니다.

실시간 통신 — WebSocket·SSE·Long Polling - 네트워크