Jerry's Log

WebSocket

contents

웹소켓(WebSocket) 은 단일하고 오래 지속되는 TCP 연결을 통해 전이중(Full-Duplex), 지속적(Persistent) 이며, 양방향 통신 채널을 제공하는 통신 프로토콜입니다. 이는 전통적인 HTTP의 요청-응답 모델의 한계를 해결하기 위해 설계되었으며, 훨씬 낮은 지연 시간과 오버헤드로 실시간 데이터 전송을 가능하게 합니다.


HTTP와의 핵심 차이점 (사용 이유)

웹소켓은 전통적인 HTTP를 사용하여 실시간 애플리케이션을 구축할 때 발생하는 비효율성을 해결하기 위해 만들어졌습니다.

특징 HTTP (전통적) 웹소켓
통신 방식 반이중 (Half-Duplex, 한 번에 한 방향만 통신) 전이중 (Full-Duplex, 양방향으로 데이터 동시 흐름)
연결 상태 무상태, 비지속적 (응답 후 매번 연결 종료) 상태 유지, 지속적 (명시적으로 닫힐 때까지 연결 유지)
서버 주도 없음 (클라이언트가 요청하기 전에는 서버가 데이터를 보낼 수 없음) 즉각적인 푸시 (서버가 언제든지 클라이언트에게 데이터를 보낼 수 있음)
오버헤드 높음 (요청/응답마다 전체 헤더 전송) 낮음 (초기 핸드셰이크 후 최소한의 프레이밍 전송)
실시간 구현 폴링(Polling) (클라이언트가 "새로운 것이 있습니까?"를 끊임없이 물어봄) 푸시(Push) (새로운 데이터가 있을 때만 서버가 전송)

아키텍처 및 핸드셰이크 (시작 방법)

웹소켓 연결은 핸드셰이크(Handshake) 라고 불리는 과정을 통해 표준 HTTP 요청으로 시작됩니다. 이 초기 교환은 하위 호환성 및 프로토콜 협상을 위해 필요합니다.

WebSocket Handshake and Connection Diagram 이미지

: 웹소켓은 단일 TCP 연결을 통해 전이중 통신 채널을 제공하는 컴퓨터 통신 프로토콜입니다. 클라이언트가 HTTP 업그레이드 요청을 통해 서버와 핸드셰이크를 시작합니다. 연결이 설정되면, 클라이언트와 서버 간의 실시간 양방향 데이터 전송이 가능해져 온라인 게임, 채팅 애플리케이션, 실시간 스포츠 업데이트와 같은 애플리케이션에 이상적입니다. 이미지에는 클라이언트, 서버, 네트워크, HTTP 업그레이드 - 핸드셰이크, 양방향 연결, 채널 닫기 레이블이 포함된 다이어그램이 있습니다.

  1. 클라이언트 요청: 클라이언트는 특정 헤더를 포함한 표준 HTTP 요청(보통 포트 80 또는 443)을 전송하여 연결을 시작합니다.
    • Upgrade: websocket: 서버에게 프로토콜을 웹소켓으로 업그레이드하고 싶다고 알립니다.
    • Connection: Upgrade: 프로토콜 업그레이드 요청을 확인합니다.
    • Sec-WebSocket-Key: 보안 검증을 위해 사용되는 고유하고 무작위로 생성된 Base64 인코딩 값입니다.
  2. 서버 응답: 서버가 프로토콜을 지원하고 요청을 수락하면, 특수 HTTP 상태 코드로 응답합니다.
    • 101 Switching Protocols: 서버가 프로토콜을 변경하고 있음을 확인합니다.
    • Sec-WebSocket-Accept: 서버는 클라이언트의 키를 기반으로 응답 해시를 계산하여 다시 보내, 핸드셰이크의 무결성을 확인합니다.
  3. 연결 설정: 클라이언트가 101 상태를 수신하면 HTTP 계층은 제거됩니다. 기본 TCP 연결은 열린 상태를 유지하며, 클라이언트와 서버 모두 이를 사용하여 경량의 웹소켓 데이터 프레임을 전송할 수 있게 됩니다.

프로토콜: 웹소켓 연결은 보안되지 않은 연결에는 ws:// 스키마를 사용하며, TLS/SSL 암호화로 보호되는 연결에는 wss:// 스키마를 사용하는데, 이는 표준적인 방식입니다.


주요 특징


사용 사례

웹소켓은 현대 실시간 웹 애플리케이션의 중추입니다.

  1. 라이브 채팅 및 메시징: 가장 명백한 사용 사례입니다. 수동으로 새로고침할 필요 없이 모든 사용자에게 메시지가 즉시 전달되고 표시되도록 보장합니다.
  2. 협업 도구: Google Docs 또는 Figma와 같이 여러 사용자가 동일한 문서를 동시에 편집하는 애플리케이션에서 사용됩니다. 한 사용자가 변경한 내용은 다른 사용자에게 즉시 푸시됩니다.
  3. 금융 및 실시간 데이터 피드: 주식 시세, 스포츠 점수 또는 센서 데이터(IoT)에 대한 지속적인 업데이트를 제공합니다.
  4. 멀티플레이어 게임: 플레이어와 서버 간의 게임 상태 동기화 시 지연 시간을 최소화하는 데 필수적입니다.

장단점 (트레이드오프)

측면 장점 (Pros) 단점 (Cons)
성능 뛰어난 속도: 지속적인 연결과 최소한의 헤더 덕분에 지연 시간이 극도로 낮습니다. 캐싱 불가: HTTP와 달리, 웹소켓 데이터는 중간 프록시에 의해 캐시될 수 없어, 서버 측에서 반복되는 데이터 관리가 필요합니다.
효율성 오버헤드 감소: 설정된 연결에 대해 반복적인 HTTP 헤더를 제거합니다. 상태 관리: 서버가 모든 개별 연결에 대한 상태와 리소스를 유지해야 하므로, 대규모에서 비용이 많이 들 수 있습니다.
통신 실시간 푸시: 서버가 언제든지 데이터 전송을 시작(푸시)할 수 있습니다. 프록시/방화벽 문제: 구형이거나 제한적인 프록시 서버는 Upgrade 헤더를 전달하거나 장시간 연결을 유지하는 데 문제가 있을 수 있습니다(현재는 드물어지고 있음).

WebSocket의 구현은 단일 TCP 소켓 위에서 작동하는 상태 머신으로 구현되며, 최소한의 오버헤드를 가진 바이너리 프레이밍 프로토콜과 보안을 위한 의무적인 페이로드 마스킹을 활용합니다.

이전에 웹소켓이 HTTP의 한계를 해결한다고 설명했지만, 실제 구현은 이전에 사용하던 HTTP 계층을 완전히 벗어나 TCP 계층에서 자체적인 규칙을 정의하는 데 중점을 둡니다.


1. 프로토콜 계층 (The Stack)

웹소켓은 통신 스택에서 다음과 같은 독특한 위치를 차지합니다.

  1. 전송 계층 (TCP): 웹소켓은 장기간 지속되는 단일 TCP 연결을 기반으로 합니다. 이 연결은 웹소켓 세션이 지속되는 동안 유지됩니다.
  2. 협상 계층 (HTTP): 연결은 Upgrade 헤더를 포함하는 일반 HTTP 요청으로 시작됩니다. 이 초기 핸드셰이크(Handshake)는 기존 네트워크 인프라(프록시, 로드 밸런서 등)와의 호환성을 위해 필요합니다.
  3. 응용 계층 (웹소켓 프레이밍): 핸드셰이크가 성공한 후, 웹소켓은 HTTP 헤더와 오버헤드를 버리고 자체적인 프레이밍 프로토콜을 사용하여 데이터를 바이너리 형식으로 송수신합니다.

2. 연결 관리 (상태 머신)

웹소켓 연결은 명확하게 정의된 상태 머신을 따릅니다. 이는 연결의 생명주기 동안 안정적인 동작을 보장합니다.


3. 데이터 프레이밍 (바이너리 구조)

웹소켓의 낮은 오버헤드는 HTTP 메시지 대신 사용되는 작고 구조화된 바이너리 프레임 덕분입니다. 각 프레임은 최소 2바이트의 헤더로 시작하며, 이 헤더에 모든 제어 정보가 담겨 있습니다.

비트 위치 (1바이트) 비트 위치 (2바이트) 내용 설명
0 (MSB) FIN 비트 1이면 이 프레임이 메시지의 마지막 프레임을 의미합니다. 0이면 메시지가 여러 프레임으로 분할(fragmentation)되었음을 의미합니다.
1-3 RSV1-3 예약 비트. 확장 기능을 협상하지 않는 한 0이어야 합니다.
4-7 Opcode (연산 코드) 프레임의 유형을 정의합니다 (텍스트, 바이너리, 핑, 퐁, 닫기 등).
8 (MSB) MASK 비트 1이면 페이로드가 마스킹되었음을 의미합니다 (클라이언트에서 서버로 가는 프레임은 필수).
9-15 페이로드 길이 페이로드 데이터의 길이를 나타냅니다. 값이 126이나 127인 경우, 추가 바이트가 필요하여 페이로드 길이가 길어짐을 나타냅니다.

4. 페이로드 마스킹 (보안 요구사항)

클라이언트에서 서버로 전송되는 모든 데이터 프레임의 페이로드는 반드시 마스킹되어야 합니다. 이는 웹소켓 프로토콜에 명시된 엄격한 보안 요구사항입니다.


5. 제어 프레임 (하트비트)

제어 프레임은 연결 자체를 관리하는 데 사용되는 특별한 프레임입니다. 이들은 항상 작고(페이로드 길이가 125바이트 미만), 조각화될 수 없습니다(FIN은 항상 1입니다).

references