실시간 알림 시스템 설계 — SSE vs WebSocket vs Polling - 코드픽 블로그
실시간 알림 시스템 설계 — SSE vs WebSocket vs Polling
기술 가이드

실시간 알림 시스템 설계 — SSE vs WebSocket vs Polling

2026년 3월 8일 39 views by 코드벤터

실시간 알림 시스템 설계 — SSE vs WebSocket vs Polling

현대 웹 애플리케이션에서 실시간은 더 이상 선택 사항이 아닌 필수 요소가 되었습니다. 새로운 메시지, 업데이트된 뉴스 피드, 주식 시세 변화, 혹은 멀티플레이어 게임의 즉각적인 반응까지, 사용자들은 즉각적인 정보 전달을 기대합니다. 이러한 실시간 경험을 제공하기 위한 핵심 기술 중 하나가 바로 실시간 알림 시스템입니다.

하지만 실시간 알림을 구현하는 방법은 다양하며, 각 방식은 고유한 장단점과 적용 시나리오를 가지고 있습니다. 무턱대고 최신 기술만을 쫓거나 가장 단순한 방법만을 고집하다가는 성능 저하, 자원 낭비, 혹은 확장성 문제를 겪을 수 있습니다.

이 글에서는 실시간 알림 시스템을 설계할 때 고려해야 할 세 가지 주요 기술인 Polling, Server-Sent Events (SSE), 그리고 WebSocket에 대해 깊이 있게 탐구합니다. 각 기술의 작동 원리, 장단점, 실제 코드 예시를 통해 명확하게 이해하고, 여러분의 프로젝트에 가장 적합한 솔루션을 선택할 수 있도록 실질적인 가이드라인을 제시하고자 합니다.

1. 실시간 알림 시스템의 필요성

오늘날 사용자들은 애플리케이션이 항상 최신 상태를 유지하고, 중요한 정보나 이벤트 발생 시 즉시 알려주기를 기대합니다. 이러한 기대치를 충족시키지 못하는 애플리케이션은 사용자 경험 저하로 이어져 결국 경쟁력을 잃게 됩니다.

  • 사용자 경험 향상: 즉각적인 알림은 사용자가 중요한 정보를 놓치지 않도록 돕고, 애플리케이션과의 상호작용을 더욱 풍부하게 만듭니다. (예: 채팅 메시지, 좋아요, 댓글 알림)
  • 비즈니스 효율성 증대: 실시간 데이터 업데이트는 주식 거래, 경매 시스템, 협업 도구 등에서 비즈니스 의사결정의 정확성과 속도를 높여줍니다.
  • 생산성 향상: 협업 도구에서 동료의 변경 사항을 실시간으로 확인하거나, 대시보드에서 시스템 상태를 즉시 모니터링하는 것은 생산성 향상에 크게 기여합니다.

이러한 요구사항을 만족시키기 위해 개발자들은 클라이언트와 서버 간의 효율적인 통신 채널을 구축해야 합니다.

2. 실시간 알림 시스템 구현 방식 비교

실시간 알림 시스템을 구현하는 방식은 크게 Polling, SSE, WebSocket 세 가지로 나눌 수 있습니다. 각각의 방식은 HTTP 프로토콜을 활용하는 정도와 통신 방향성에서 차이를 보입니다.

2.1. Polling (폴링)

Polling은 가장 전통적이고 단순한 실시간 데이터 업데이트 방식입니다. 클라이언트가 주기적으로 서버에 새로운 데이터가 있는지 요청하고, 서버는 요청 시점의 최신 데이터를 응답합니다.

개념

클라이언트가 setInterval과 같은 함수를 사용하여 정해진 시간 간격(예: 5초마다)으로 서버의 특정 API 엔드포인트에 HTTP GET 요청을 보냅니다. 서버는 요청을 받으면 현재 가지고 있는 최신 정보를 응답하고, 클라이언트는 이 정보를 화면에 반영합니다.

장점

  • 구현 단순성: 특별한 프로토콜이나 API 없이 표준 HTTP 요청(XMLHttpRequest 또는 Fetch API)만으로 구현할 수 있습니다.
  • 모든 브라우저 지원: HTTP 요청을 보내는 방식이므로 사실상 모든 웹 브라우저에서 문제없이 작동합니다.
  • 방화벽 친화적: 표준 HTTP 포트(80, 443)를 사용하므로 방화벽이나 프록시 서버에 의해 차단될 가능성이 적습니다.

단점

  • 비효율적인 자원 소모:
    • 서버 부하: 새로운 데이터가 없더라도 클라이언트의 주기적인 요청에 계속 응답해야 하므로 서버에 불필요한 부하를 줍니다. 특히 클라이언트 수가 많아지면 요청 수가 기하급수적으로 늘어납니다.
    • 네트워크 트래픽: 요청-응답 헤더가 매번 전송되므로 불필요한 네트워크 트래픽이 발생합니다.
  • 높은 지연 시간 (Latency): 데이터가 업데이트되는 즉시 알림을 받을 수 없습니다. 다음 폴링 주기까지 기다려야 하므로 실시간성이 떨어집니다. 폴링 주기를 짧게 하면 서버 부하와 트래픽이 증가하고, 길게 하면 지연 시간이 늘어나는 trade-off가 발생합니다.
  • 잦은 연결/해제: 매 요청마다 TCP 연결을 맺고 끊는 오버헤드가 발생합니다.

언제 사용하는가?

  • 낮은 실시간성 요구: 데이터 업데이트가 자주 일어나지 않거나, 약간의 지연이 허용되는 경우 (예: 관리자 페이지의 통계 업데이트, 1분 단위로 갱신되는 정보).
  • 구현 복잡도를 최소화해야 할 때: 다른 실시간 기술 도입이 어렵거나, 비용 대비 효과가 낮은 경우.

코드 예시 (JavaScript)

javascript
// 클라이언트 측 JavaScript
function fetchData() {
    fetch(/api/notifications)
        .then(response => response.json())
        .then(data => {
            console.log(새로운 알림:, data);
            // 알림 데이터를 UI에 표시하는 로직
            document.getElementById(notification-count).innerText = data.count;
            if (data.messages.length > 0) {
                const ul = document.getElementById(notification-list);
                ul.innerHTML = ; // 기존 알림 초기화
                data.messages.forEach(msg => {
                    const li = document.createElement(li);
                    li.innerText = msg;
                    ul.appendChild(li);
                });
            }
        })
        .catch(error => console.error(Error fetching notifications:, error));
}

// 5초(5000ms)마다 fetchData 함수 호출
setInterval(fetchData, 5000);

// 초기 로드 시 한 번 호출
fetchData();
html
<!-- HTML 구조 예시 -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Polling Example</title>
</head>
<body>
    <h1>Polling 기반 실시간 알림</h1>
    <p>현재 알림 수: <span id="notification-count">0</span></p>
    <h2>최신 알림</h2>
    <ul id="notification-list">
        <li>알림이 없습니다.</li>
    </ul>
    <script src="client.js"></script>
</body>
</html>
python
# 서버 측 Python (Flask 예시)
from flask import Flask, jsonify
import time
import random

app = Flask(__name__)

# 가상의 알림 데이터
notifications = []
last_notification_id = 0

def add_random_notification():
    global last_notification_id
    last_notification_id += 1
    notifications.append(f"새로운 알림 {last_notification_id}: {time.strftime(%H:%M:%S)}")
    if len(notifications) > 5: # 최대 5개 유지
        notifications.pop(0)

# 10초마다 새로운 알림을 추가하는 백그라운드 작업 (실제 환경에서는 DB나 메시지 큐에서 가져옴)
import threading
def notification_generator():
    while True:
        time.sleep(random.randint(5, 15)) # 5~15초마다 알림 생성
        add_random_notification()
        print(f"Server generated new notification. Current notifications: {notifications}")

notification_thread = threading.Thread(target=notification_generator)
notification_thread.daemon = True
notification_thread.start()


@app.route(/api/notifications)
def get_notifications():
    # 실제 환경에서는 last_read_id 같은 파라미터를 받아 새로운 알림만 필터링할 수 있음
    return jsonify({
        count: len(notifications),
        messages: notifications
    })

if __name__ == __main__:
    app.run(debug=True, port=5000)

위 예시에서 클라이언트는 5초마다 /api/notifications 엔드포인트에 요청을 보내고, 서버는 현재 가지고 있는 알림 목록을 반환합니다.

2.2. Long Polling (롱 폴링)

Long Polling은 Polling의 비효율성을 개선한 방식입니다. 클라이언트가 서버에 요청을 보냈을 때, 서버는 즉시 응답하지 않고 새로운 데이터나 이벤트가 발생할 때까지 연결을 열어 둡니다. 데이터가 발생하면 서버는 응답을 보내고, 클라이언트는 응답을 받은 후 즉시 새로운 Long Polling 요청을 다시 보냅니다.

개념

클라이언트가 서버에 HTTP 요청을 보냅니다. 서버는 응답할 데이터가 없으면 요청을 "보류" 상태로 유지합니다. 일정 시간(타임아웃)이 지나거나, 새로운 데이터가 발생하면 서버는 보류 중인 요청에 데이터를 담아 응답합니다. 클라이언트는 이 응답을 처리한 후, 또다시 새로운 Long Polling 요청을 서버에 보냅니다. 이 과정을 반복하여 거의 실시간에 가까운 통신을 구현합니다.

장점

  • Polling보다 효율적: 데이터가 없는 경우에도 계속 요청을 보내는 Polling과 달리, 실제 데이터가 있을 때만 응답이 오므로 불필요한 트래픽과 서버 부하를 줄일 수 있습니다.
  • 낮은 지연 시간: 데이터 발생 즉시 알림을 받을 수 있어 Polling보다 실시간성이 높습니다.
  • 광범위한 호환성: Polling과 마찬가지로 표준 HTTP 프로토콜을 사용하므로 대부분의 브라우저와 네트워크 환경에서 잘 작동합니다.

단점

  • 서버 자원 소모: 서버는 응답할 데이터가 없는 동안 클라이언트의 연결을 계속 유지해야 하므로, 많은 클라이언트가 동시에 연결되어 있으면 서버 자원(메모리, 소켓) 소모가 커집니다.
  • 복잡한 서버 구현: 타임아웃 처리, 연결 관리, 데이터 발생 시 보류 중인 모든 클라이언트에게 응답 보내기 등 서버 측 로직이 Polling보다 복잡합니다.
  • 연결 끊김 처리: 네트워크 문제 등으로 연결이 끊겼을 때 클라이언트가 재연결 요청을 다시 보내는 로직이 필요합니다.

언제 사용하는가?

  • 중간 정도의 실시간성 요구: Polling보다는 높은 실시간성이 필요하지만, WebSocket만큼의 완전한 양방향 통신이나 낮은 오버헤드가 필수는 아닌 경우.
  • 오래된 브라우저나 네트워크 환경 지원이 필요한 경우: WebSocket이 지원되지 않는 환경에서 실시간 기능을 제공해야 할 때 유용합니다. (최신 브라우저에서는 대부분 WebSocket을 지원합니다.)
  • 채팅 애플리케이션: 과거에는 많은 채팅 서비스에서 Long Polling을 사용하여 메시지를 수신했습니다.

코드 예시 (개념 설명 위주)

Long Polling은 서버 측에서 연결을 관리하고 타임아웃을 처리하는 복잡한 로직이 필요하므로, 여기서는 클라이언트 측의 요청 흐름을 간략하게 보여줍니다.

javascript
// 클라이언트 측 JavaScript (개념)
function longPoll() {
    fetch(/api/longpoll/notifications)
        .then(response => response.json())
        .then(data => {
            if (data.messages && data.messages.length > 0) {
                console.log(새로운 알림 수신 (Long Polling):, data);
                // UI 업데이트 로직
            }
            // 응답을 받으면 즉시 다음 Long Polling 요청 시작
            longPoll();
        })
        .catch(error => {
            console.error(Long Polling Error:, error);
            // 에러 발생 시 일정 시간 후 재시도
            setTimeout(longPoll, 3000);
        });
}

// 초기 시작
longPoll();
python
# 서버 측 Python (Flask + threading/queue를 이용한 Long Polling 개념)
from flask import Flask, request, jsonify
import time
import random
from collections import deque
import threading

app = Flask(__name__)

# 알림을 저장할 큐 (스레드 세이프)
notification_queue = deque()
# 보류 중인 클라이언트 요청을 저장할 리스트
waiting_clients = []
waiting_clients_lock = threading.Lock() # 리스트 접근 보호

# 새로운 알림을 생성하고 대기 중인 클라이언트에게 알리는 함수
def generate_notification():
    global notification_queue
    while True:
        time.sleep(random.randint(5, 10)) # 5~10초마다 알림 생성
        msg = f"새로운 알림 {len(notification_queue) + 1}: {time.strftime(%H:%M:%S)}"
        notification_queue.append(msg)
        print(f"Server generated new notification: {msg}")

        # 대기 중인 모든 클라이언트에게 알림
        with waiting_clients_lock:
            for client_event in list(waiting_clients): # 리스트 복사 후 순회
                client_event.set() # 이벤트 발생 시킴
            waiting_clients.clear() # 모든 클라이언트에게 알렸으므로 리스트 비움

notification_thread = threading.Thread(target=generate_notification)
notification_thread.daemon = True
notification_thread.start()

@app.route(/api/longpoll/notifications)
def long_poll_notifications():
    # 클라이언트별 이벤트 객체 생성 (데이터가 올 때까지 대기)
    client_event = threading.Event()

    with waiting_clients_lock:
        waiting_clients.append(client_event)

    # 최대 20초 동안 데이터가 오기를 기다림
    # 20초 안에 데이터가 오면 client_event.set()에 의해 대기 해제
    # 20초가 지나면 타임아웃으로 대기 해제
    event_received = client_event.wait(timeout=20)

    with waiting_clients_lock:
        if client_event in waiting_clients:
            waiting_clients.remove(client_event) # 타임아웃으로 해제된 경우 리스트에서 제거

    if event_received: # 데이터가 도착하여 이벤트가 발생한 경우
        messages = list(notification_queue)
        notification_queue.clear() # 큐 비우기
        return jsonify({messages: messages, status: success})
    else: # 타임아웃된 경우
        return jsonify({messages: [], status: timeout})

if __name__ == __main__:
    app.run(debug=True, port=5000)

서버는 클라이언트의 요청이 들어오면 threading.Event 객체를 생성하고, 이 이벤트를 waiting_clients 리스트에 추가합니다. 새로운 알림이 생성되면 이 이벤트를 set()하여 클라이언트의 대기를 해제하고, 클라이언트에게 알림을 전달합니다. 일정 시간(timeout) 동안 알림이 없으면, 서버는 빈 응답을 보내고 클라이언트는 다시 요청을 보냅니다.

2.3. Server-Sent Events (SSE)

**Server-Sent Events (SSE)**는 서버에서 클라이언트로의 단방향 스트림 통신을 위한 기술입니다. 이름에서 알 수 있듯이, 서버가 클라이언트에게 이벤트를 전송하는 데 특화되어 있습니다. HTTP/1.1 프로토콜 위에서 동작하며, EventSource API를 통해 구현됩니다.

개념

클라이언트가 서버에 HTTP 요청을 보내면, 서버는 응답 헤더에 Content-Type: text/event-stream을 지정하고, 연결을 닫지 않은 채로 열어 둡니다. 이후 서버는 새로운 이벤트가 발생할 때마다 미리 정해진 data: 접두사를 붙인 텍스트 메시지를 이 열린 연결을 통해 클라이언트에 지속적으로 스트리밍합니다. 클라이언트는 EventSource 객체를 통해 이벤트를 수신하고 처리합니다.

장점

  • 단순한 구현 (클라이언트 측): EventSource API는 매우 직관적이며, 연결 관리, 자동 재연결(네트워크 문제 발생 시), 마지막 이벤트 ID 추적 등의 기능을 내장하고 있어 클라이언트 측 구현이 매우 간단합니다.
  • HTTP/1.1 기반: 기존 HTTP 프로토콜 위에서 동작하므로 방화벽이나 프록시 서버에 대한 호환성이 높습니다. 별도의 프로토콜 업그레이드 과정이 필요 없습니다.
  • 낮은 오버헤드: WebSocket에 비해 연결 설정 및 유지에 필요한 오버헤드가 적습니다.
  • 텍스트 데이터에 최적화: 주로 텍스트 기반의 실시간 알림, 뉴스 피드, 대시보드 업데이트 등에 적합합니다.

단점

  • 단방향 통신: 서버에서 클라이언트로만 데이터 전송이 가능합니다. 클라이언트에서 서버로 데이터를 보내려면 별도의 HTTP 요청(Fetch, XMLHttpRequest)을 사용해야 합니다.
  • 바이너리 데이터 전송 어려움: 텍스트 기반이므로 이미지, 동영상 등 바이너리 데이터 전송에는 적합하지 않습니다.
  • 동시 연결 수 제한: 대부분의 브라우저는 한 도메인당 최대 6~8개의 SSE 연결을 허용합니다. 이는 WebSocket에 비해 제한적일 수 있습니다. (하지만 이는 HTTP/1.1 Keep-Alive 연결 제한과 유사하며, HTTP/2를 사용하면 다중 스트림으로 이 제한을 우회할 수 있습니다.)

언제 사용하는가?

  • 서버 -> 클라이언트 단방향 데이터 스트리밍: 뉴스 피드, 주식 시세, 스포츠 스코어, 실시간 대시보드, 알림 서비스, 채팅방의 메시지 수신 등 서버가 주도적으로 클라이언트에 정보를 푸시해야 하는 경우.
  • 구현 복잡도를 낮추면서 실시간 기능을 구현하고 싶을 때.
  • HTTP/2 환경: HTTP/2는 단일 TCP 연결 위에서 여러 스트림을 멀티플렉싱하므로, SSE의 동시 연결 수 제한을 완화할 수 있습니다.

코드 예시 (JavaScript 클라이언트, Python Flask 서버)

javascript
// 클라이언트 측 JavaScript
const eventSource = new EventSource(/api/sse/notifications);

eventSource.onopen = () => {
    console.log(SSE 연결이 열렸습니다.);
};

eventSource.onmessage = (event) => {
    // message 이벤트 수신
    console.log(새로운 기본 알림:, event.data);
    const ul = document.getElementById(notification-list);
    const li = document.createElement(li);
    li.innerText = `[기본] ${event.data}`;
    ul.appendChild(li);
};

eventSource.addEventListener(customEvent, (event) => {
    // customEvent 타입의 이벤트 수신
    console.log(새로운 사용자 정의 알림 (customEvent):, event.data);
    const ul = document.getElementById(notification-list);
    const li = document.createElement(li);
    li.innerText = `[사용자 정의] ${event.data}`;
    ul.appendChild(li);
});

eventSource.onerror = (error) => {
    console.error(SSE 연결 오류:, error);
    // 오류 발생 시 EventSource는 자동으로 재연결을 시도합니다.
};

// 연결 종료 시 (명시적으로 닫거나 서버에서 연결을 끊을 때)
// eventSource.close();
html
<!-- HTML 구조 예시 -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SSE Example</title>
</head>
<body>
    <h1>SSE 기반 실시간 알림</h1>
    <h2>최신 알림</h2>
    <ul id="notification-list">
    </ul>
    <script src="client.js"></script>
</body>
</html>
python
# 서버 측 Python (Flask 예시)
from flask import Flask, Response
import time
import random

app = Flask(__name__)

def generate_sse_events():
    event_id = 0
    while True:
        time.sleep(random.randint(2, 5)) # 2~5초마다 이벤트 발생
        event_id += 1

        # 기본 message 이벤트
        yield f"id: {event_id}\ndata: 서버에서 보낸 일반 알림 {time.strftime(%H:%M:%S)}\n\n"

        # 특정 타입의 이벤트 (클라이언트에서 addEventListener로 수신)
        if event_id % 3 == 0:
            yield f"id: {event_id}-custom\nevent: customEvent\ndata: 특별 이벤트 발생! {time.strftime(%H:%M:%S)}\n\n"

@app.route(/api/sse/notifications)
def sse_notifications():
    # Content-Type을 text/event-stream으로 설정하여 SSE임을 알림
    # Cache-Control: no-cache는 클라이언트가 응답을 캐싱하지 않도록 함
    return Response(generate_sse_events(), mimetype=text/event-stream, headers={
        Cache-Control: no-cache,
        X-Accel-Buffering: no # Nginx 등의 프록시에서 버퍼링을 끄도록 지시
    })

if __name__ == __main__:
    app.run(debug=True, port=5000)

서버는 /api/sse/notifications 요청에 대해 text/event-stream MIME 타입을 가진 Response 객체를 반환합니다. generate_sse_events 함수는 무한 루프를 돌며 yield 키워드를 통해 이벤트를 스트리밍합니다. 각 이벤트는 id:, event:, data: 형식으로 구성되어야 합니다.

2.4. WebSocket

WebSocket은 클라이언트와 서버 간의 양방향, 전이중 통신 채널을 제공하는 고급 프로토콜입니다. 한 번 연결이 설정되면 클라이언트와 서버는 독립적으로 언제든지 서로에게 데이터를 주고받을 수 있습니다.

개념

WebSocket 연결은 HTTP 핸드셰이크로 시작됩니다. 클라이언트가 서버에 HTTP 요청(Upgrade 헤더 포함)을 보내면, 서버는 이를 수락하고 HTTP 프로토콜에서 WebSocket 프로토콜로 전환(Upgrade)합니다. 이 과정이 성공하면, 기존 HTTP 연결은 닫히고 양방향으로 데이터를 주고받을 수 있는 영구적인 TCP 연결이 수립됩니다. 이 연결은 일반 HTTP 요청-응답 주기 없이 낮은 오버헤드로 데이터를 지속적으로 교환할 수 있습니다.

장점

  • 양방향, 전이중 통신: 클라이언트와 서버가 동시에 독립적으로 데이터를 주고받을 수 있어 진정한 실시간 상호작용이 가능합니다.
  • 낮은 오버헤드: 핸드셰이크 이후에는 HTTP 헤더 없이 작은 프레임으로 데이터를 전송하므로 네트워크 오버헤드가 매우 낮습니다.
  • 실시간성 극대화: 데이터 발생 즉시 양방향으로 전송되므로 지연 시간이 거의 없습니다.
  • 바이너리 데이터 전송: 텍스트뿐만 아니라 바이너리 데이터도 효율적으로 전송할 수 있습니다.
  • 다양한 애플리케이션: 실시간 채팅, 멀티플레이어 게임, 온라인 협업 도구, 실시간 위치 추적 등 고성능 실시간 통신이 필요한 모든 애플리케이션에 적합합니다.

단점

  • 구현 복잡성: HTTP와 다른 별도의 프로토콜이므로, 서버와 클라이언트 모두 WebSocket 프로토콜을 처리하는 라이브러리나 프레임워크를 사용해야 합니다.
  • 방화벽/프록시 문제: 일부 오래된 방화벽이나 프록시는 WebSocket 연결을 지원하지 않거나, 특정 포트를 차단할 수 있습니다. (대부분의 최신 환경에서는 문제없습니다.)
  • 연결 관리: 연결 끊김, 재연결, 메시지 유실, 보안 등 복잡한 연결 관리 로직을 직접 구현하거나 라이브러리의 도움을 받아야 합니다.
  • 상대적으로 높은 초기 오버헤드: HTTP 핸드셰이크 과정이 필요하며, 장기간 연결 유지를 위한 서버 자원(소켓) 소모가 SSE나 Polling보다 클 수 있습니다.

언제 사용하는가?

  • 양방향 실시간 상호작용이 필수적인 경우: 실시간 채팅, 멀티플레이어 온라인 게임, 화상 회의, 실시간 협업 문서 편집.
  • 낮은 지연 시간과 높은 처리량이 요구되는 경우: 금융 거래 시스템, 실시간 대시보드에서 빈번하게 업데이트되는 데이터.
  • 텍스트 외 바이너리 데이터 전송이 필요한 경우.

코드 예시 (JavaScript 클라이언트, Python websockets 라이브러리 서버)

javascript
// 클라이언트 측 JavaScript
const socket = new WebSocket(ws://localhost:8000/ws);

socket.onopen = (event) => {
    console.log(WebSocket 연결이 열렸습니다.);
    socket.send(안녕하세요, 서버!); // 연결 후 서버로 메시지 전송
};

socket.onmessage = (event) => {
    console.log(서버로부터 메시지 수신:, event.data);
    const ul = document.getElementById(message-list);
    const li = document.createElement(li);
    li.innerText = event.data;
    ul.appendChild(li);
};

socket.onclose = (event) => {
    if (event.wasClean) {
        console.log(`WebSocket 연결이 정상적으로 닫혔습니다. 코드: ${event.code}, 이유: ${event.reason}`);
    } else {
        console.error(WebSocket 연결이 예기치 않게 끊어졌습니다.);
    }
    // 연결이 끊겼을 때 재연결 로직 구현 가능
    setTimeout(() => {
        console.log(재연결 시도...);
        // 새로운 WebSocket 객체 생성 또는 기존 객체 재사용 시도
        // 이 예시에서는 단순화를 위해 재연결 코드를 생략합니다.
    }, 3000);
};

socket.onerror = (error) => {
    console.error(WebSocket 오류 발생:, error);
};

// 서버로 메시지 보내는 함수
function sendMessage() {
    const input = document.getElementById(message-input);
    const message = input.value;
    if (message) {
        socket.send(message);
        input.value = ;
    }
}

// Enter 키로 메시지 전송
document.getElementById(message-input).addEventListener(keypress, (e) => {
    if (e.key === Enter) {
        sendMessage();
    }
});
html
<!-- HTML 구조 예시 -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebSocket Example</title>
</head>
<body>
    <h1>WebSocket 기반 실시간 채팅</h1>
    <div>
        <input type="text" id="message-input" placeholder="메시지를 입력하세요">
        <button onclick="sendMessage()">전송</button>
    </div>
    <h2>메시지 목록</h2>
    <ul id="message-list">
    </ul>
    <script src="

개발 의뢰 상담

AI 서비스나 플랫폼 개발을
고민 중이신가요?

CodePick에서는
기획 → 개발 → 운영까지 함께합니다.
아이디어만 있어도 상담 가능합니다.

CodeVenter 개발팀이 직접 담당 · 1~2 영업일 내 회신

✓ 스타트업 MVP 개발✓ AI 서비스 개발✓ 웹 플랫폼 개발✓ 기업 시스템 구축✓ 모바일 앱 개발

AI Development Studio

코드픽 by 코드벤터

  • 대표: 윤승환 · 사업자등록번호: 121-57-64983
  • 대구광역시 중구 국채보상로 586, 16층 · info@codeventer.com

© 2025 코드벤터. All rights reserved.