웹소켓(영어: WebSocket)은 단일 TCP 연결로 동시양방향통신 채널을 제공하는 컴퓨터 통신 프로토콜이다. 웹소켓 프로토콜은 2011년 IETF에 의해 RFC 6455로 표준화되었으며 웹 IDL의 웹소켓 API는 W3C에 의해 표준화되고 있다.

한마디로 말하면, HTTP의 한계를 뛰어넘어 실시간 양방향 통신을 가능하게 하는 마법 같은 기술이다. 더 이상 새로고침 버튼을 광클할 필요가 없다

개요[편집 / 원본 편집]

웹소켓을 사용하면 서버와 브라우저 간 연결을 유지한 상태로 데이터를 교환할 수 있다. 이때 데이터는 '패킷(packet)' 형태로 전달되며, 전송은 커넥션 중단과 추가 HTTP 요청 없이 양방향으로 이뤄진다.

필요성[편집 / 원본 편집]

기존의 HTTP 통신은 요청-응답 방식의 단방향 통신이었다. 클라이언트가 요청을 보내야만 서버가 응답하는 구조로, 실시간 통신에는 매우 비효율적이었다. 마치 편지를 주고받는 것처럼 느렸다

예를 들어 채팅 애플리케이션을 만들려면:

  1. 폴링(Polling): 주기적으로 서버에 "새 메시지 있어?" 하고 물어보기
  2. 롱 폴링(Long Polling): 새 메시지가 올 때까지 요청을 계속 유지하기
  3. Server-Sent Events: 서버에서 클라이언트로만 데이터 전송

하지만 이런 방법들은 모두 한계가 있었다. HTTP 프로토콜은 전통적인 웹사이트를 구현하는데 최적화된 통신 모델이다. 웹페이지를 제공할 때 서버에서는 클라이언트와 연결을 지속할 이유가 없다.

웹소켓은 이러한 문제를 해결하기 위해 등장했다. 웹소켓 프로토콜은 클라이언트와 서버 간에 보다 효율적인 실시간 양방향 통신을 가능하게 하는 웹 표준 기술이다.

동작 원리[편집 / 원본 편집]

핸드셰이크 과정[편집 / 원본 편집]

웹소켓은 HTTP와 완전히 별개의 프로토콜이 아니다. 웹소켓은 HTTP와 완전 별개의 프로토콜로 보시기 보다는 HTTP 통신이 진화(upgrade)한 형태라고 보시는 것이 좋다.

웹소켓 연결 과정은 다음과 같다:

클라이언트의 업그레이드 요청[편집 / 원본 편집]

클라이언트는 서버로 GET 방식으로 요청을 보내는데, 이때 Connection과 Upgrade와 같이 웹소켓에서만 쓰이는 조금 특별한 헤더를 함께 보낸다.

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

각 헤더의 의미:

  • Connection: Upgrade: 클라이언트 측에서 프로토콜을 바꾸고 싶다는 신호를 보냈다는 것을 나타낸다
  • Upgrade: websocket: 클라이언트측에서 요청한 프로토콜은 'websocket'이라는걸 의미한다
  • Sec-WebSocket-Key: 보안을 위해 브라우저에서 생성한 키로, 서버가 웹소켓 프로토콜을 지원하는지를 확인하는데 사용된다
  • Sec-WebSocket-Version: 웹소켓 프로토콜 버전이 명시된다. 예시에서 버전은 13이다

서버의 응답[편집 / 원본 편집]

웹소켓 연결을 지원하는 서버라면 이 경우 101 Switching Protocols 상태 코드를 응답해준다.

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

여기서 Sec-WebSocket-Accept값은 특별한 알고리즘을 사용해 만든 Sec-WebSocket-Key 이다. 이 값을 보고 브라우저는 서버가 진짜 웹소켓 프로토콜을 지원하는지 확인한다.

이렇게 본격적인 웹소켓 통신을 시작하기 전에 클라이언트와 서버가 간단히 HTTP로 메시지를 주고 받는 것을 보통 핸드쉐이크(handshake)라고도 한다.

마치 처음 만난 사람과 악수하는 것처럼 정중하다

데이터 전송[편집 / 원본 편집]

핸드셰이크가 완료되면 이제 진짜 웹소켓 통신이 시작된다. 웹소켓 통신은 '프레임(frame)'이라 불리는 데이터 조각을 사용해 이뤄진다.

프레임의 종류:

  • 텍스트 프레임(text frame): 텍스트 데이터가 담긴 프레임
  • 이진 데이터 프레임(binary data frame): 이진 데이터가 담긴 프레임
  • 핑·퐁 프레임(ping/pong frame): 커넥션이 유지되고 있는지 확인할 때 사용하는 프레임으로 서버나 브라우저에서 자동 생성해서 보내는 프레임

장점과 특징[편집 / 원본 편집]

주요 장점[편집 / 원본 편집]

  1. 실시간 양방향 통신: HTTP의 요청-응답 패턴에서 벗어나 실시간으로 데이터를 주고받을 수 있다.
  2. 낮은 오버헤드: 연결이 한 번 맺어지면 HTTP 헤더 없이 데이터만 주고받을 수 있어 효율적이다.
  3. HTTP 호환성: 웹소켓은 HTTP 포트 80과 443 위에 동작하도록 설계되었으며 HTTP 프록시 및 중간 층을 지원하도록 설계되었으므로 HTTP 프로토콜과 호환이 된다
  4. 방화벽 친화적: HTTP와 같은 포트를 사용하므로 대부분의 방화벽에서 차단되지 않는다.

활용 분야[편집 / 원본 편집]

이런 특징 때문에 웹소켓은 온라인 게임이나 주식 트레이딩 시스템같이 데이터 교환이 지속적으로 이뤄져야 하는 서비스에 아주 적합하다

주요 활용 사례:

채팅 애플리케이션[편집 / 원본 편집]

사용자가 실시간으로 메시지, 이모지, 이미지, 비디오 또는 오디오를 전송하고 수신할 수 있는 채팅 애플리케이션을 만드는 데 사용될 수 있다. 웹소켓은 또한 사용자가 동시에 여러 사람과 통신할 수 있는 단체 채팅, 비디오 채팅 또는 음성 채팅 애플리케이션 생성에도 사용될 수 있다.

실시간 알림 시스템[편집 / 원본 편집]

새 메시지, 새 팔로워, 새 좋아요, 새 댓글 또는 새 주문과 같은 중요한 이벤트에 대해 사용자에게 경고하는 알림 시스템을 생성하는 데 사용될 수 있다.

금융 거래 시스템[편집 / 원본 편집]

시세나 주문, 체결 등의 실시간 정보를 빠르고 편리하게 수신하고자 한다면 REST API보다는 WebSocket API의 사용을 권장한다

온라인 게임[편집 / 원본 편집]

실시간 멀티플레이어 게임에서 플레이어들 간의 상호작용을 처리하는 데 필수적이다.

프로토콜 스킴[편집 / 원본 편집]

웹소켓 URI에는 2가지의 종류가 있는데 ws://로 시작하는 경우와 wss://로 시작하는 경우다. ws은 WebSocket의 약자이고, wss는 WebSocket Secure의 약자이며 그냥 HTTP, HTTPS와 같은 개념인 것이다.

ws://[편집 / 원본 편집]

  • 암호화되지 않은 웹소켓 연결
  • HTTP와 유사하게 80번 포트 사용
  • 개발 환경이나 내부 네트워크에서 주로 사용

wss://[편집 / 원본 편집]

  • TLS/SSL로 암호화된 웹소켓 연결
  • HTTPS와 유사하게 443번 포트 사용
  • 프로덕션 환경에서 권장

wss://는 보안 이외에도 신뢰성(reliability) 측면에서 ws보다 좀 더 신뢰할만한 프로토콜이다. ws://를 사용해 데이터를 전송하면 데이터가 암호화되어있지 않은 채로 전송되기 때문에 데이터가 그대로 노출된다.

보안을 신경쓰는 HTTPS를 사용하는 웹 사이트의 경우에는 ws대신 wss를 써야 한다. 웹소켓 클라이언트를 연결할 때 wss가 아니면 연결 시도조차 되지 않기 때문이다.

브라우저 지원 현황[편집 / 원본 편집]

2025년 현재 웹소켓은 모든 주요 브라우저에서 지원된다:

Firefox 버전 8이상도 이를 금지한다 - 혼합 콘텐츠(Mixed Content) 상황에서의 보안 정책을 의미한다.

웹소켓 API 사용법[편집 / 원본 편집]

기본 사용법[편집 / 원본 편집]

연결 생성[편집 / 원본 편집]

// 기본 연결
const socket = new WebSocket('ws://localhost:8080');

// 보안 연결 (권장)
const socket = new WebSocket('wss://example.com/socket');

// 서브 프로토콜 지정
const socket = new WebSocket('wss://example.com/socket', ['protocol1', 'protocol2']);

이벤트 처리[편집 / 원본 편집]

웹소켓에서는 네 가지 주요 이벤트를 처리할 수 있다:

// 연결 성공 시
socket.onopen = function(event) {
    console.log('웹소켓 연결 성공!');
};

// 메시지 수신 시  
socket.onmessage = function(event) {
    console.log('받은 메시지:', event.data);
};

// 에러 발생 시
socket.onerror = function(error) {
    console.error('웹소켓 에러:', error);
};

// 연결 종료 시
socket.onclose = function(event) {
    console.log('웹소켓 연결 종료');
    console.log('코드:', event.code, '이유:', event.reason);
};

데이터 전송[편집 / 원본 편집]

// 텍스트 전송
socket.send('안녕하세요!');

// JSON 데이터 전송
socket.send(JSON.stringify({
    type: 'message',
    content: '실시간 메시지입니다!'
}));

// 이진 데이터 전송
const buffer = new ArrayBuffer(32);
socket.send(buffer);

연결 종료[편집 / 원본 편집]

// 정상 종료
socket.close();

// 종료 코드와 이유 지정
socket.close(1000, '정상 종료');

연결 상태 확인[편집 / 원본 편집]

웹소켓의 연결 상태는 readyState 속성으로 확인할 수 있다:

switch(socket.readyState) {
    case WebSocket.CONNECTING:
        console.log('연결 중...');
        break;
    case WebSocket.OPEN:
        console.log('연결됨');
        break;
    case WebSocket.CLOSING:
        console.log('종료 중...');
        break;
    case WebSocket.CLOSED:
        console.log('연결 종료됨');
        break;
}

서버 측 구현[편집 / 원본 편집]

Node.js + ws 라이브러리[편집 / 원본 편집]

가장 기본적인 Node.js 웹소켓 서버 구현:

const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', function connection(ws) {
    console.log('새 클라이언트 접속');
    
    // 메시지 수신
    ws.on('message', function incoming(message) {
        console.log('받은 메시지:', message.toString());
        
        // 모든 클라이언트에게 브로드캐스트
        wss.clients.forEach(function each(client) {
            if (client !== ws && client.readyState === WebSocket.OPEN) {
                client.send(message);
            }
        });
    });
    
    // 연결 종료
    ws.on('close', function close() {
        console.log('클라이언트 연결 종료');
    });
});

Express와 함께 사용[편집 / 원본 편집]

Express.js 서버와 웹소켓을 함께 사용하는 예제:

const express = require('express');
const WebSocket = require('ws');
const http = require('http');

const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });

// 웹소켓 로직
wss.on('connection', function connection(ws, req) {
    const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
    console.log('새로운 클라이언트 접속:', ip);
    
    ws.on('message', function incoming(message) {
        console.log('받은 메시지:', message.toString());
    });
});

// HTTP 라우트
app.get('/', (req, res) => {
    res.send('웹소켓 서버가 실행 중입니다!');
});

server.listen(3000, () => {
    console.log('서버가 3000번 포트에서 실행 중입니다.');
});

주요 라이브러리와 프레임워크[편집 / 원본 편집]

Socket.IO[편집 / 원본 편집]

socket.io는 양방햔 통신을 하기위해 웹소켓 기술을 활용하는 라이브러리이다. 어찌보면 자바스크립트jQuery의 관계와 비슷하다고 할 수 있겠다.

Socket.IO의 특징[편집 / 원본 편집]

Socket.IO는 웹소켓의 부가기능이 아니다. 웹소켓은 Socket.IO가 실시간, 양방향, 이벤트 기반 통신을 제공하는 방법 중 하나이다. 만약 당신의 브라우저나 기기가 웹소켓을 지원하지 않는다면 Socket.IO는 다른 방법을 사용해서 계속 동작할 것이다.

주요 기능:

  • 자동 재연결: 연결이 끊어져도 자동으로 재시도
  • 폴백 지원: 웹소켓이 지원되지 않을 때 HTTP Long Polling 사용
  • 룸(Room) 기능: 특정 사용자 그룹에게만 메시지 전송
  • 이벤트 기반 통신: 직관적인 이벤트 방식

Socket.IO vs 순수 웹소켓[편집 / 원본 편집]

ws는 조금 불친절하지만 원하는대로 코드 작성하기가 쉬웠고, socket.io는 기능이 많고 쉽게 사용하기 쉬우며 직관적이다. 처음 배우기에 확실히 좋은건 socket.io, 원하는대로 커스텀하여 만들기 좋은 것은 ws라고 할 수 있다.

Socket.IO 장점:

  • 소켓 연결 실패 시 fallback을 통해 다른 방식으로 알아서 해당 클라이언트와 연결을 시도함
  • 방 개념을 이용해 일부 클라이언트에게만 데이터를 전송하는 브로드캐스팅이 가능함
  • 이벤트 기반의 직관적인 API

순수 웹소켓 장점:

  • 가벼움 (추가 라이브러리 불필요)
  • 표준 기술
  • 더 나은 성능

Socket.IO 사용 예제[편집 / 원본 편집]

서버 측:

const io = require('socket.io')(3000);

io.on('connection', (socket) => {
    console.log('사용자 연결됨:', socket.id);
    
    // 특정 룸에 입장
    socket.join('room1');
    
    // 메시지 처리
    socket.on('message', (data) => {
        // 같은 룸의 다른 사용자들에게 전송
        socket.to('room1').emit('message', data);
    });
    
    // 연결 해제
    socket.on('disconnect', () => {
        console.log('사용자 연결 해제됨:', socket.id);
    });
});

클라이언트 측:

const socket = io('http://localhost:3000');

// 연결 성공
socket.on('connect', () => {
    console.log('서버에 연결됨!');
});

// 메시지 전송
socket.emit('message', { text: '안녕하세요!' });

// 메시지 수신
socket.on('message', (data) => {
    console.log('받은 메시지:', data);
});

기타 라이브러리들[편집 / 원본 편집]

ws (Node.js)[편집 / 원본 편집]

  • 가장 인기 있는 Node.js 웹소켓 라이브러리
  • 빠르고 가벼움
  • 순수 웹소켓 표준 구현

uWebSockets.js[편집 / 원본 편집]

  • 고성능 웹소켓 라이브러리
  • C++로 작성된 바인딩
  • 대용량 트래픽 처리에 적합

SockJS[편집 / 원본 편집]

  • 웹소켓 호환성을 위한 라이브러리
  • 다양한 폴백 옵션 제공
  • 브라우저 호환성 중시

보안 고려사항[편집 / 원본 편집]

Origin 검증[편집 / 원본 편집]

서버는 Origin 헤더를 보고 어떤 웹사이트와 소켓통신을 할지 결정하기 때문에 Origin 헤더는 웹소켓 통신에 중요한 역할을 한다.

서버에서 Origin을 검증하는 예제:

const wss = new WebSocket.Server({
    port: 8080,
    verifyClient: (info) => {
        const origin = info.origin;
        const allowedOrigins = ['https://example.com', 'https://app.example.com'];
        return allowedOrigins.includes(origin);
    }
});

인증과 인가[편집 / 원본 편집]

웹소켓 연결에서의 사용자 인증:

const wss = new WebSocket.Server({
    port: 8080,
    verifyClient: (info, callback) => {
        // 토큰 검증
        const token = info.req.url.split('token=')[1];
        
        if (isValidToken(token)) {
            callback(true);
        } else {
            callback(false, 401, 'Unauthorized');
        }
    }
});

Rate Limiting[편집 / 원본 편집]

DoS 공격 방지를 위한 연결 수 제한:

const connections = new Map();

wss.on('connection', (ws, req) => {
    const ip = req.connection.remoteAddress;
    const connectionCount = connections.get(ip) || 0;
    
    if (connectionCount >= 10) {
        ws.close(1008, 'Too many connections');
        return;
    }
    
    connections.set(ip, connectionCount + 1);
    
    ws.on('close', () => {
        connections.set(ip, connections.get(ip) - 1);
    });
});

CSRF 방지[편집 / 원본 편집]

웹소켓은 SOP(Same-Origin Policy)의 영향을 받지 않으므로 CSRF 공격에 취약할 수 있다. 적절한 토큰 검증이 필요하다.

성능 최적화[편집 / 원본 편집]

메시지 압축[편집 / 원본 편집]

Sec-WebSocket-Extensions: deflate-frame – 이 헤더는 브라우저에서 데이터 압축(deflate)을 지원한다는 것을 의미한다.

const wss = new WebSocket.Server({
    port: 8080,
    perMessageDeflate: {
        // 압축 설정
        threshold: 1024,
        concurrencyLimit: 10,
        memLevel: 7
    }
});

연결 풀링[편집 / 원본 편집]

서버에서 연결을 효율적으로 관리:

class WebSocketManager {
    constructor() {
        this.connections = new Set();
        this.rooms = new Map();
    }
    
    addConnection(ws, userId) {
        this.connections.add(ws);
        ws.userId = userId;
        
        ws.on('close', () => {
            this.connections.delete(ws);
        });
    }
    
    broadcast(message) {
        this.connections.forEach(ws => {
            if (ws.readyState === WebSocket.OPEN) {
                ws.send(message);
            }
        });
    }
}

Heartbeat 메커니즘[편집 / 원본 편집]

연결 상태를 확인하기 위한 ping/pong:

function heartbeat() {
    this.isAlive = true;
}

wss.on('connection', (ws) => {
    ws.isAlive = true;
    ws.on('pong', heartbeat);
});

// 30초마다 ping 전송
const interval = setInterval(() => {
    wss.clients.forEach((ws) => {
        if (ws.isAlive === false) {
            return ws.terminate();
        }
        
        ws.isAlive = false;
        ws.ping();
    });
}, 30000);

디버깅과 테스트[편집 / 원본 편집]

브라우저 개발자 도구[편집 / 원본 편집]

Chrome 개발자 도구에서 웹소켓 연결을 확인하는 방법:

  1. F12로 개발자 도구 열기
  2. Network 탭 선택
  3. WS (WebSocket) 필터 적용
  4. 연결된 웹소켓의 프레임 확인 가능

테스트 도구[편집 / 원본 편집]

wscat[편집 / 원본 편집]

명령줄에서 웹소켓을 테스트할 수 있는 도구:

# 설치
npm install -g wscat

# 연결 테스트
wscat -c ws://localhost:8080

# 메시지 전송
> hello world

Postman[편집 / 원본 편집]

GUI 환경에서 웹소켓을 테스트할 수 있다. 최신 버전에서 웹소켓 지원을 추가했다.

온라인 테스트 도구[편집 / 원본 편집]

  • websocket.org/echo.html
  • www.websocket.org/echo.html

한계와 단점[편집 / 원본 편집]

브라우저 제한사항[편집 / 원본 편집]

일부 웹 브라우저가 지원하지 않는다. 하지만 2025년에 IE를 쓰는 사람은 거의 없다

프록시와 방화벽 문제[편집 / 원본 편집]

아주 오래된 프락시 서버는 웹소켓이 무엇인지 몰라서 '이상한' 헤더가 붙은 요청이 들어왔다고 판단하고 연결을 끊어버린다.

상태 관리의 복잡성[편집 / 원본 편집]

HTTP와 달리 상태를 유지하므로:

  • 서버 재시작 시 모든 연결 손실
  • 로드 밸런싱이 복잡해짐
  • 메모리 사용량 증가

스케일링 문제[편집 / 원본 편집]

대규모 서비스에서는:

  • 연결 수 제한
  • 서버 간 메시지 동기화 필요
  • RedisRabbitMQ 같은 메시지 브로커 필요

대안 기술들[편집 / 원본 편집]

Server-Sent Events (SSE)[편집 / 원본 편집]

서버에서 클라이언트로만 데이터를 보내는 단방향 통신:

// 서버 측 (Express)
app.get('/events', (req, res) => {
    res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive'
    });
    
    const data = `data: ${JSON.stringify({ message: '안녕하세요!' })}\n\n`;
    res.write(data);
});

// 클라이언트 측
const eventSource = new EventSource('/events');
eventSource.onmessage = function(event) {
    console.log(JSON.parse(event.data));
};

장점: 구현이 간단, 자동 재연결
단점: 단방향 통신만 가능

HTTP/2 Server Push[편집 / 원본 편집]

HTTP/2의 서버 푸시 기능을 활용한 실시간 데이터 전송:

// HTTP/2 서버 푸시 예제
const http2 = require('http2');

const server = http2.createSecureServer(options);

server.on('stream', (stream, headers) => {
    if (headers[':path'] === '/') {
        // 메인 페이지와 함께 필요한 리소스를 푸시
        stream.pushStream({ ':path': '/style.css' }, (err, pushStream) => {
            if (!err) {
                pushStream.respondWithFile('/path/to/style.css');
            }
        });
    }
});

gRPC Streaming[편집 / 원본 편집]

고성능 RPC 프레임워크의 스트리밍 기능:

// gRPC 양방향 스트리밍
const grpc = require('grpc');

function chatStream(call) {
    call.on('data', (message) => {
        console.log('받은 메시지:', message);
        call.write({ text: '응답 메시지' });
    });
    
    call.on('end', () => {
        call.end();
    });
}

미래 전망과 발전 방향[편집 / 원본 편집]

HTTP/3과 QUIC[편집 / 원본 편집]

HTTP/3QUIC 프로토콜의 등장으로 웹소켓의 역할이 변화할 수 있다:

  • 더 빠른 연결 설정
  • 패킷 손실에 대한 더 나은 복구
  • 다중 스트림 지원

WebTransport[편집 / 원본 편집]

차세대 웹 전송 API로, 웹소켓의 일부 한계를 해결:

  • UDP 기반 전송 지원
  • 더 낮은 지연 시간
  • 더 유연한 전송 모드

WebRTC Data Channel[편집 / 원본 편집]

P2P 통신을 위한 대안:

  • 서버를 거치지 않는 직접 통신
  • 더 낮은 지연 시간
  • 브라우저 간 직접 데이터 교환

실제 사용 사례와 성공 사례[편집 / 원본 편집]

Discord[편집 / 원본 편집]

대표적인 실시간 채팅 플랫폼으로, 웹소켓을 활용해:

  • 실시간 메시지 전송
  • 음성 채팅 상태 동기화
  • 사용자 온라인 상태 관리

Slack[편집 / 원본 편집]

비즈니스 커뮤니케이션 도구로:

  • 실시간 메시지 알림
  • 파일 업로드 상태 표시
  • 사용자 타이핑 상태 표시

온라인 게임[편집 / 원본 편집]

  • Agar.io: 실시간 멀티플레이어 게임
  • Slither.io: 대규모 동시 접속자 처리
  • 각종 브라우저 기반 MMORPG

금융 거래 플랫폼[편집 / 원본 편집]

코빗 가상자산 거래소의 실시간 정보를 가장 빠른 속도로 수신할 수 있다

  • 실시간 주가 정보
  • 거래 체결 알림
  • 포트폴리오 변동 사항

같이 보기[편집 / 원본 편집]

각주[편집 / 원본 편집]


외부 링크[편집 / 원본 편집]