본문으로 건너뛰기
yutils

websocket vs SSE — 실시간 통신은 어떻게 동작할까?

양방향 WebSocket vs 단방향 Server-Sent Events — handshake · frame format · 재연결 · heartbeat 차이, 채팅 · 알림 · 실시간 대시보드에 어떤 걸 골라야 할지.

약 8분 읽기

채팅·실시간 알림·라이브 대시보드 — server 가 client 에 데이터를 push 해야 한다. HTTP 의 request/response 패턴으로는 어려움. 답은 WebSocket 또는 Server-Sent Events (SSE). 둘이 어떻게 다른가? HTTP 위에서 어떻게 양방향 통신이 가능한가? 이 가이드는 WebSocket handshake, SSE EventSource, long polling 의 비교, 그리고 어떤 상황에 무엇을 쓸지 정리한다.

왜 HTTP 만으로 부족한가

HTTP 기본 패턴:
Client → Request → Server
Server → Response → Client
                    ↓ connection close

채팅 messages 받으려면?
- 매 1 초마다 polling?
  → 99% 빈 응답, 부하 폭주
- server 가 client 에 직접 push?
  → 어떻게? client 의 IP/port 모름, NAT 뒤

실시간 통신 = "server 가 데이터 push" + "client 가 data send" 둘 다.

옛 해결책 — Long Polling

Client → GET /messages?since=0  (HTTP)
Server: 응답 보류 (open connection)
  ...
  새 메시지 도착!
Server → 200 OK, {messages: [...]}
       ↓ connection close

Client → GET /messages?since=last  (즉시 다시)
...

장점 — HTTP 만 사용, proxy / firewall 호환. 단점:

  • 매 message 마다 connection 새로 → overhead
  • HTTP header 반복 (kB 씩)
  • server 가 응답 보류 중 timeout 위험

2010 이전에는 표준. 지금은 fallback only.

WebSocket — 양방향 single connection

2011 표준 (RFC 6455). HTTP 위 handshake 한 번 → connection 을 WebSocket 으로 "upgrade" → 양방향 byte stream:

Client → GET /ws HTTP/1.1
        Host: example.com
        Upgrade: websocket
        Connection: Upgrade
        Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
        Sec-WebSocket-Version: 13

Server → HTTP/1.1 101 Switching Protocols
        Upgrade: websocket
        Connection: Upgrade
        Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

→ 이제 같은 TCP connection 으로 WebSocket frame 양방향 송수신

Sec-WebSocket-Accept = client 의 Key 와 magic string 결합 후 SHA-1. 단순 echo 가 아닌 처리로 cache proxy 가 잘못 응답 못 함.

WebSocket frame 형식

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| op    |M| Payload len |    Extended payload length    |
|I|S|S|S| code  |A|     (7)     |             (16/64)           |
|N|V|V|V|  (4)  |S|             |                               |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+-------------------------------+

op code:
  0x1 = text frame (UTF-8)
  0x2 = binary frame
  0x8 = close frame
  0x9 = ping frame
  0xA = pong frame

매 frame 2-14 byte overhead (HTTP header 의 200-2000 byte 대비 훨씬 적음). 초당 수천 메시지 가능.

WebSocket 클라이언트 코드

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

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

ws.onmessage = (event) => {
  console.log("받은 메시지:", event.data);
};

ws.onclose = (event) => {
  console.log("연결 종료:", event.code, event.reason);
};

ws.onerror = (event) => {
  console.error("에러:", event);
};

Server-Sent Events (SSE) — 단방향 server push

2009 W3C 표준. HTTP 의 long-running response 활용 + 표준 라이브 러리 wrapper:

Client:
const source = new EventSource("/events");
source.onmessage = (e) => {
  console.log("server 가 보낸:", e.data);
};

Server (Node):
res.writeHead(200, {
  "Content-Type": "text/event-stream",
  "Cache-Control": "no-cache",
  "Connection": "keep-alive",
});

// 매 event 마다
res.write(`data: ${JSON.stringify(msg)}\n\n`);
// 연결 유지, 닫지 않음

Wire format — 단순 text:

event: chat-message
data: {"user":"Alice","text":"hi"}
id: 42

event: notification
data: New user joined
id: 43

(blank line 으로 event 구분)

SSE 의 강점

  • HTTP 위 — 별도 protocol X, proxy / firewall 호환 ↑
  • 자동 재연결 — EventSource 가 connection drop 감지 후 자동 재연결. Last-Event-ID 헤더로 미수신 event 복구
  • browser 표준 API — EventSource. 라이브러리 X

SSE 의 약점

  • 단방향만 — server → client. client → server 는 별도 HTTP POST
  • browser connection 제한 — domain 당 6 개 (HTTP/1.1). 여러 tab 의 SSE 가 모두 같은 domain 이면 한도 hit
  • binary 미지원 — text/event-stream 만, base64 필요

WebSocket vs SSE — 매트릭스

WebSocketSSE
방향양방향server → client 만
Protocolws:// / wss://http:// / https://
BinaryX (base64 필요)
자동 재연결수동 구현✅ 내장
Proxy / Firewall가끔 blockedHTTP — 통과 잘됨
Multiplexconnection 1 + topicconnection 마다 별개
Overhead per message2-14 byte~50 byte (text framing)
HTTP/2 multiplexingX (별도 protocol)✅ (HTTP/2)
Server 구현전용 library (Socket.IO, ws)표준 HTTP, 라이브러리 X

언제 어떤 것

WebSocket 권장

  • 채팅 (양방향, low latency)
  • 실시간 multi-player 게임
  • collaborative editing (Google Docs)
  • trading / 금융 ticker (대량 binary)

SSE 권장

  • 알림 (server → client 만)
  • 실시간 dashboard (stock price, server metrics)
  • activity feed (Twitter, GitHub 알림)
  • build / job progress (CI 로그 stream)
  • client → server 는 적은 (form 제출 등 일반 HTTP)

그 외 후보

  • WebRTC — peer-to-peer + UDP. 음성·영상·게임 저지연. server 부담 ↓.
  • HTTP/2 Server Push — preload 용. 일반 실시간 X. deprecated by Chrome (2022).
  • Long polling — 옛 fallback. 모던 환경에서는 last resort.

실용 — Heartbeat 와 reconnection

WebSocket — ping/pong

Server → ping frame (op 0x9)
Client → pong frame (op 0xA) 자동 응답

30 초 이상 pong 안 옴 → connection dead, 재연결

Cloudflare / nginx 가 idle connection 60-100 초 timeout 으로 kill — heartbeat 30 초 주기 필수.

SSE — 자동 재연결

server: 빈 comment 으로 heartbeat
: heartbeat

client EventSource:
- connection drop 감지
- retry: 3000 (server 가 지정 가능)
- 3 초 후 자동 재연결
- Last-Event-ID 헤더에 마지막 받은 id 박음
- server 가 미수신 event 부터 다시 보냄

인증·security

  • WebSocket — handshake 의 HTTP request 에 cookie / token 박힘. 첫 메시지로 auth 또는 query param 으로 token
  • SSE — HTTP 그대로, cookie / Authorization 자연 동작

WebSocket 의 함정 — Origin 헤더 검증 안 하면 CSWSH (Cross-Site WebSocket Hijacking) 공격. SSE 는 CORS 적용.

흔한 함정

1. browser connection 한도

HTTP/1.1 에서 domain 당 6 connection. SSE 여러 개 + 일반 fetch 병행 시 hit. HTTP/2 는 multiplex 로 해결.

2. CDN / Proxy 의 buffering

nginx / Cloudflare 의 default buffer 가 SSE response 모아서 보냄 → 실시간 X. X-Accel-Buffering: no header + proxy 설정.

3. WebSocket 재연결 폭주

Server outage 후 모든 client 가 동시 재연결 시도 → thundering herd → server 또 down. exponential backoff + jitter 필수.

4. Memory leak

Client side WebSocket 의 message handler 가 closure 로 outer scope 변수 capture → GC 안 됨. 명시적 ws.close() + listener 제거.

5. Backpressure

Server 가 slow client 에 빠르게 send → 메시지 buffer 폭주. drop oldest 또는 throttling.

참고 자료

  • RFC 6455 (WebSocket) — datatracker
  • MDN — Server-Sent Events — MDN
  • MDN — WebSockets API — MDN
  • WHATWG HTML — EventSource spec — WHATWG

요약

  • 실시간 통신 옵션 — long polling (옛) / WebSocket (양방향) / SSE (단방향) / WebRTC (peer-to-peer).
  • WebSocket = HTTP 위 handshake → 양방향 binary/text frame. ws:// / wss:// protocol. 채팅 / 게임 / 양방향.
  • SSE = HTTP long-running response + text/event-stream. EventSource API. 단방향, 자동 재연결, proxy 호환 ↑.
  • 매 message overhead — WebSocket 2-14 byte vs SSE 50 byte vs HTTP 1-2 KB. WebSocket 가장 효율적.
  • SSE 가 단방향 + HTTP 호환 + 자동 재연결로 단순. 알림 / 대시보드 에 first choice.
  • Heartbeat 필수 — WebSocket ping/pong, SSE comment.
  • CDN / proxy 의 buffering 주의 — X-Accel-Buffering: no
  • 재연결 시 exponential backoff + jitter — thundering herd 방지.
가이드 목록으로