WebSocket 프로토콜 완벽 가이드

WebSocket은 웹 애플리케이션에서 실시간 양방향 통신을 구현하기 위한 표준 프로토콜이다. 전통적인 HTTP 통신이 클라이언트의 요청-서버 응답 패턴에 의존하는 반면, WebSocket은 하나의 TCP 연결을 통해 서버와 클라이언트가 서로 독립적으로 데이터를 전송할 수 있는 전이중 통신을 지원한다.

WebSocket 프로토콜의 핵심 특성

WebSocket은 OSI 7계층 모델의 애플리케이션 층에 위치하는 프로토콜로서, TCP 기반의 영구 연결을 구축한다. 이 프로토콜의 가장 큰 장점은 연결 수립 후 클라이언트와 서버 모두 상대방에게 먼저 데이터를 전송할 수 있다는 점이다. 또한 HTTP와 달리 통신 과정에서 전송되는 제어 프레임의 크기가 매우 작아 오버헤드를 최소화할 수 있다.

주요 특징은 다음과 같다:

  • TCP 프로토콜을 기반으로 동작
  • 프로토콜 식별자는 ws이며, 암호화 버전은 wss
  • 동일 출처 정책(Same-Origin Policy)의 제한을 받지 않아 도메인 간 통신 가능
  • 상태를 유지하는 연결로 통신 시 상태 정보 재전송 불필요
  • 텍스트와 바이너리 데이터 모두 전송 지원

WebSocket 연결 구현

연결 수립

JavaScript에서 WebSocket 객체 생성자를 사용하여 서버와의 연결을 초기화한다.

// 서버 엔드포인트 주소로 WebSocket 클라이언트 생성
const socket = new WebSocket('wss://api.example.com:8443/ws');

// 연결 객체 상태 확인
console.log(socket);

연결 객체에는 연결 상태, 수신 데이터 처리 콜백, 프로토콜 정보 등의 속성이 포함되어 있다.

연결 상태 및 이벤트 처리

상태 코드 의미
0 연결 수립 중
1 연결 완료, 통신 가능
2 연결 종료 대기 중
3 연결 종료됨
const socket = new WebSocket('wss://api.example.com:8443/ws');

// 연결 성공 시 실행
socket.addEventListener('open', function(event) {
    console.log('서버 연결 성공');
    socket.send('안녕하세요!');
});

// 오류 발생 시 실행
socket.addEventListener('error', function(event) {
    console.log('연결 오류 발생:', event);
});

// 메시지 수신 시 실행
socket.addEventListener('message', function(event) {
    console.log('서버からのメッセージ:', event.data);
});

// 연결 종료 시 실행
socket.addEventListener('close', function(event) {
    console.log('연결 종료:', event.code, event.reason);
});

자동 재연결 구현

네트워크 문제나 서버 재시작 등으로 연결이 끊어질 수 있으므로, 연결 종료를 감지하여 자동으로 재연결을 시도하는 로직이 필요하다.

class WebSocketClient {
    constructor(url) {
        this.url = url;
        this.connect();
    }

    connect() {
        this.socket = new WebSocket(this.url);
        
        this.socket.addEventListener('open', () => {
            console.log('연결 성공');
            this.heartbeat();
        });

        this.socket.addEventListener('close', (event) => {
            console.log('연결 종료, 재연결 시도...');
            setTimeout(() => this.connect(), 5000);
        });

        this.socket.addEventListener('message', (event) => {
            console.log('수신:', event.data);
        });
    }

    heartbeat() {
        if (this.heartbeatTimer) {
            clearTimeout(this.heartbeatTimer);
        }
        
        this.heartbeatTimer = setInterval(() => {
            if (this.socket.readyState === WebSocket.OPEN) {
                this.socket.send('PING');
            }
        }, 30000);
    }

    send(data) {
        if (this.socket.readyState === WebSocket.OPEN) {
            this.socket.send(JSON.stringify(data));
        }
    }

    disconnect() {
        if (this.heartbeatTimer) {
            clearInterval(this.heartbeatTimer);
        }
        this.socket.close();
    }
}

Keep-Alive 메커니즘

장시간 연결이 유지되면 서버나 네트워크 장비에서 연결을 자동으로 종료할 수 있다. 이를 방지하기 위해 주기적으로 Ping/Pong 메시지를 교환하는 Keep-Alive 메커니즘을 구현한다.

function startHeartbeat(connection, interval = 30000) {
    let timerId = null;
    
    const sendHeartbeat = () => {
        if (connection.readyState === WebSocket.OPEN) {
            connection.send(JSON.stringify({ type: 'heartbeat' }));
        }
    };
    
    timerId = setInterval(sendHeartbeat, interval);
    
    return () => {
        if (timerId) {
            clearInterval(timerId);
        }
    };
}

// 사용 예시
const ws = new WebSocket('wss://api.example.com:8443/ws');
const stopHeartbeat = startHeartbeat(ws);

// 연결 종료 시Heartbeat 중지
ws.addEventListener('close', stopHeartbeat);

인증 토큰 전달 방법

WebSocket 연결 시 인증이 필요한 경우, 여러 가지 방법으로 토큰을 전달할 수 있다.

방법 1: 연결 수립 후 메시지로 전송

const ws = new WebSocket('wss://api.example.com:8443/ws');
const authToken = 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';

ws.addEventListener('open', () => {
    ws.send(JSON.stringify({
        type: 'auth',
        token: authToken
    }));
});

방법 2: 쿼리 파라미터로 전달

const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';
const ws = new WebSocket(`wss://api.example.com:8443/ws?token=${encodeURIComponent(token)}`);

방법 3: 서브프로토콜 이용

const ws = new WebSocket('wss://api.example.com:8443/ws', ['jwt', 'token']);

WebSocket 프로토콜은 실시간 채팅 애플리케이션, 실시간 데이터 시각화, 온라인 게임, 알림 시스템 등 다양한 분야에서 활용되며, 현대 웹 개발에서 필수적인 기술로 자리잡았다.

태그: websocket realtime-communication html5 JavaScript network-protocol

6월 3일 16:11에 게시됨