WebSocket 이해하기

HTTP Upgrade 핸드셰이크(101), Sec-WebSocket-Key/Accept, 프레임 구조, ws:// vs wss://, WebSocket과 SSE·long-polling 비교, 서브프로토콜, 스케일링을 다룹니다.

WebSocket은 하나의 TCP 연결 위에서 클라이언트와 서버가 양방향으로 언제든 메시지를 주고받을 수 있는 전이중(full-duplex) 프로토콜입니다. 요청-응답 한 쌍이 기본 단위인 HTTP와 달리, 연결을 한 번 맺으면 서버가 클라이언트의 요청 없이도 먼저 데이터를 밀어 보낼 수 있어 채팅·실시간 알림·협업 편집·게임 등에 적합합니다.

HTTP Upgrade 핸드셰이크 (101)

WebSocket 연결은 놀랍게도 평범한 HTTP 요청으로 시작합니다. 클라이언트가 Upgrade: websocket 헤더로 프로토콜 전환을 요청하면, 서버가 동의할 경우 101 Switching Protocols로 응답하고, 그 시점부터 같은 TCP 연결이 HTTP를 벗어나 WebSocket 프레임을 주고받는 통로로 바뀝니다.

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

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

Sec-WebSocket-Key와 Accept

핸드셰이크의 Sec-WebSocket-Key는 보안 토큰이 아니라, 응답하는 상대가 진짜 WebSocket을 이해하는 서버인지 확인하기 위한 값입니다. 서버는 클라이언트가 보낸 키에 고정 GUID 258EAFA5-E914-47DA-95CA-C5AB0DC85B11를 이어 붙여 SHA-1 해시를 구하고, 그 결과를 Base64로 인코딩해 Sec-WebSocket-Accept로 돌려줍니다. 클라이언트가 같은 계산을 해서 값이 맞으면, 우연히 열린 HTTP 서버가 아니라 제대로 된 WebSocket 서버임을 확신할 수 있습니다.

프레임

핸드셰이크 이후의 데이터는 HTTP가 아니라 경량 프레임(frame) 단위로 흐릅니다. 각 프레임에는 opcode가 있어 텍스트(0x1)·바이너리(0x2)·연결 종료(0x8)·ping(0x9)·pong(0xA)을 구분합니다. 큰 메시지는 여러 프레임으로 쪼갤 수 있고, FIN 비트로 마지막 조각을 표시합니다. 클라이언트→서버 프레임은 반드시 마스킹(masking)되어야 하는데, 이는 중간 프록시가 트래픽을 HTTP로 오인해 캐시를 오염시키는 공격을 막기 위한 규정입니다.

ws:// vs wss://

URL 스킴은 두 가지입니다. ws://는 평문, wss://는 TLS 위에서 암호화된 WebSocket입니다. HTTPS와 HTTP의 관계와 같으며, 실무에서는 도청·프록시 간섭·혼합 콘텐츠 문제를 피하기 위해 항상 wss://를 써야 합니다. HTTPS 페이지에서 ws://로 접속을 시도하면 혼합 콘텐츠로 차단됩니다.

WebSocket vs SSE vs long-polling

실시간 통신 방식은 여러 가지이고, 요구사항에 따라 선택이 갈립니다.

서브프로토콜과 스케일링

WebSocket은 프레임의 전송만 정의할 뿐 그 안의 메시지 의미는 정하지 않습니다. 애플리케이션은 Sec-WebSocket-Protocol 헤더로 서브프로토콜(예: graphql-ws, MQTT-over-WS 등)을 협상해 메시지 형식을 합의합니다. 스케일링은 까다로운데, WebSocket은 오래 유지되는 상태 있는(stateful) 연결이라 무상태 HTTP처럼 아무 서버로나 라우팅할 수 없습니다. 여러 서버로 확장하려면 로드밸런서의 sticky 세션, 그리고 서버 간에 메시지를 팬아웃할 pub/sub 백플레인(예: Redis)이 필요합니다. 연결 수가 많으면 파일 디스크립터·메모리 한계도 함께 관리해야 합니다.