Web Socket과 STOMP 이해하기
실시간 통신의 핵심 기술인 Web Socket과 이를 보완 및 표준화하기 위해 활용되는 STOMP (Simple Text Oriented Messaging Protocol)에 대한 동작 방식과 특징에 대해 알아보자.
1. Web Socket 개요
Web Socket은 클라이언트와 서버 간에 지속적인 연결을 유지하며 양방향 통신 (Full-Duplex)을 가능하게 하는 프로토콜이다. 2011년 RFC 6455로 표준화되어, 실시간 애플리케이션(예: 채팅, 게임, 주식 거래 등)에서 빠르고 효율적인 데이터 교환 수단으로 자리 잡았다.
- HTTP와 달리, 한 번의 핸드쉐이크로 지속적인 연결을 유지하며 클라이언트와 서버가 서로 자유롭게 데이터를 주고받을 수 있다.
- 실시간 처리:
메시지 전송 지연 없이 양쪽 모두 동시에 데이터를 송수신할 수 있어, 빠른 응답이 요구되는 환경에 적합하다.
2. Web Socket의 특징
Web Socket의 주요 특징을 정리하면 다음과 같다.
- 양방향 통신 (Full-Duplex)
클라이언트와 서버 모두 언제든 데이터를 전송할 수 있으며, 요청-응답 구조에 얽매이지 않는다. - 낮은 오버헤드
HTTP의 경우 매 요청마다 헤더 정보가 포함되지만, Web Socket은 최초의 핸드쉐이크 이후 불필요한 헤더 없이 간결한 프레임 단위로 데이터를 전송한다. - 실시간 네트워킹
짧은 시간 안에 다수의 클라이언트와 빠르게 데이터를 교환할 수 있어, 실시간 채팅, 스트리밍, 온라인 게임 등에서 뛰어난 성능을 발휘한다. - 표준화된 프로토콜
RFC 6455로 표준화되어 있어 다양한 브라우저와 서버 환경에서 일관되게 동작하며, 안정적인 통신을 보장한다.
3. HTTP 기반 실시간 통신 기술과의 비교
Web Socket 이전에는 HTTP를 기반으로 한 여러 실시간 통신 기법이 사용되었다. 각 기법은 장단점을 가지고 있으며, Web Socket이 이를 보완하는 방식으로 발전해왔다.
Polling
- 원리:
클라이언트가 일정 간격으로 서버에 요청하여 최신 데이터를 확인하는 방식이다. - 문제점:
지속적인 요청으로 인한 불필요한 네트워크 오버헤드와 서버 부하가 발생한다.
Long Polling
- 원리:
클라이언트가 서버에 요청을 보내고, 서버는 새로운 데이터가 있을 때까지 응답을 지연시킨 후 응답을 보낸다. 응답 후 연결을 끊고, 다시 요청하는 방식이다. - 문제점:
데이터 양이 많아지면 일반 Polling과 유사한 부하가 발생하며, 연결 유지 관리가 복잡해진다.
Server-Sent Events (SSE)
- 원리:
클라이언트가 서버에 단일 연결을 요청한 후, 서버가 해당 연결을 통해 지속적으로 이벤트를 전송하는 방식이다. - 문제점:
단방향 통신으로, 클라이언트가 서버로 데이터를 보내기에는 제약이 있다.
위와 같은 HTTP 기반 방식은 헤더 정보의 중복 전송과 연결 재설정 등에서 효율성이 떨어지며, 실시간성이 중요한 애플리케이션에서는 한계점을 보인다.
4. Web Socket의 동작 과정
Web Socket 통신은 크게 핸드쉐이킹 (Opening Handshake), 데이터 전송 (Data Transfer), 연결 종료 (Close Handshake)의 세 단계로 이루어진다.
4.1 핸드쉐이킹 (Opening Handshake)
클라이언트는 HTTP 요청을 통해 Web Socket 연결을 요청한다. 아래는 예시의 요청이다.
GET /chat HTTP/1.1
Host: localhost:8080
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://localhost:9000
- Upgrade & Connection 헤더:
프로토콜 전환 요청임을 명시한다. 헤더 값이 올바르지 않으면 연결이 거부된다. - Sec-WebSocket-Key:
클라이언트가 생성한 임의의 값을 Base64로 인코딩한 것으로, 서버는 이를 이용해 응답 값을 생성해 클라이언트를 인증한다. - Sec-WebSocket-Protocol:
클라이언트가 사용하고자 하는 서브 프로토콜 목록을 제시하며, 서버는 지원 가능한 프로토콜을 선택하여 응답한다.
서버는 아래와 같이 응답하여 연결 설정한다.
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
- Sec-WebSocket-Accept:
클라이언트가 보낸 Sec-WebSocket-Key에 특정 문자열(예: "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")를 결합 후 SHA-1 해싱하고 Base64 인코딩하여 생성된다. 클라이언트는 이 값을 검증하여 서버의 응답이 유효함을 확인한다.
4.2 데이터 전송 (Data Transfer)
연결 수립 이후, 통신은 ws 또는 wss 프로토콜로 전환된다.
데이터는 프레임(Frame) 단위로 전송되며, 하나의 메시지는 여러 프레임으로 구성될 수 있다.
- 프레임 구조:
각 프레임은 다음과 같은 필드를 포함한다.- FIN (Final): 해당 프레임이 메시지의 마지막 프레임임을 표시한다.
- Opcode: 프레임의 타입을 나타낸다.
예) 0x1: 텍스트 데이터, 0x2: 이진 데이터, 0x8: 연결 종료 요청 등. - Masking: 클라이언트에서 서버로 전송되는 모든 프레임은 마스킹 처리되어 전송된다.
- Payload Length: 실제 데이터의 길이를 나타낸다.
- Payload Data: 전송되는 실제 데이터 (텍스트 또는 이진 데이터).
이와 같이 프레임 단위로 데이터를 송수신함으로써, Web Socket은 실시간성이 요구되는 환경에서 최소의 오버헤드로 효율적인 통신을 가능하게 한다.
4.3 연결 종료 (Close Handshake)
양측 중 어느 한 쪽이 연결 종료를 원할 때, Close Frame을 전송한다.
연결 종료 요청을 받은 쪽은 반드시 Close Frame으로 응답하여, 정상적으로 연결이 종료되도록 한다.
이 과정에서 종료 코드와 이유 메시지를 포함할 수 있으며, 이를 통해 연결 종료의 원인을 명확히 전달할 수 있다.
5. Socket.io와 SockJS
Web Socket이 등장하기 전이나, 혹은 Web Socket이 지원되지 않는 환경에서는 다양한 폴백(fallback) 기술을 통해 유사한 실시간 통신 기능을 구현하였다.
Socket.io
- 특징:
단일 API를 통해 Web Socket, AJAX Long Polling, FlashSocket 등 다양한 전송 기법을 자동으로 선택하여 사용한다.
또한, 자동 재연결, 네임스페이스, 룸 기능 등 실시간 애플리케이션 개발에 유용한 다양한 기능을 제공한다. - 장점:
복잡한 네트워크 환경에서도 안정적으로 실시간 통신을 구현할 수 있으며, 클라이언트와 서버 간의 연결 상태를 세밀하게 관리할 수 있다.
SockJS
- 특징:
Web Socket API를 에뮬레이션하여, 브라우저 호환성 문제를 해결하기 위한 라이브러리이다.
내부적으로 XHR 스트리밍, XHR 폴링, JSONP 폴링 등 다양한 전송 방식을 지원하여, 클라이언트와 서버 간의 연결을 유지한다. - 장점:
Web Socket을 지원하지 않는 브라우저나 제한된 네트워크 환경에서도 원활한 통신을 가능하게 하며, STOMP와 결합하여 메시지 기반의 통신을 구현할 때 유용하다.
이 두 라이브러리는 Web Socket이 가지는 한계를 보완하면서, 다양한 환경에서 실시간 통신을 구현할 수 있도록 돕는다.
6. STOMP (Simple Text Oriented Messaging Protocol)
Web Socket은 데이터 전송의 효율성을 제공하지만, 메시지의 구조나 형식에 대한 명세는 없다.
이러한 문제를 해결하기 위해 등장한 것이 바로 STOMP이다.
STOMP의 개념 및 필요성
- 목적:
클라이언트와 서버 간에 주고받는 메시지의 형식을 표준화하여, 명확한 커맨드와 헤더 구조를 통해 데이터의 의미를 전달하고, 메시지 브로커를 통한 Publish-Subscribe 구조를 구현하기 위함이다. - 사용 환경:
TCP, Web Socket 등 다양한 양방향 통신 프로토콜 위에서 동작하며, 특히 Spring 기반의 서버에서는 STOMP를 통해 손쉽게 실시간 메시징 시스템을 구축할 수 있다.
STOMP의 프레임 구조
STOMP 메시지는 세 가지 주요 부분으로 구성된다.
1. Command
- 메시지의 동작을 정의하며, 대표적으로 CONNECT, SEND, SUBSCRIBE, UNSUBSCRIBE, DISCONNECT 등이 있다.
- 예시:
CONNECT
accept-version:1.2
host:localhost
^@
2. Header
- key-value 쌍의 형태로 메시지에 부가 정보를 전달한다.
- Command와 Body 사이에 빈 줄을 두어 구분하며, 각 헤더는 개행 문자로 분리된다.
3. Body
- 실제 전송할 데이터를 포함하며, 마지막은 반드시 NULL 문자로 종료되어 프레임의 끝을 알린다.
- 예시:
SEND
destination:/topic/chat
Hello, STOMP!^@
STOMP 기반 통신 흐름
STOMP는 주로 메시지 브로커를 활용한 Publish-Subscribe 모델을 채택한다.
통신 과정은 다음과 같이 진행된다.
- 연결 수립
- 클라이언트는 CONNECT 커맨드를 통해 서버와 연결을 수립하고, 이후 인증 및 세션 관리를 진행한다.
- 구독 (Subscribe)
- 클라이언트는 특정 목적지(예: /topic/chat)를 구독하기 위해 SUBSCRIBE 커맨드를 전송한다.
- 서버는 해당 경로로 전송되는 메시지를 해당 클라이언트에 전달한다.
- 메시지 발행 (Send)
- 클라이언트 또는 다른 발행자가 SEND 커맨드를 통해 메시지를 전송하면, 서버 혹은 메시지 브로커는 이를 처리 후 구독 중인 클라이언트들에게 전달한다.
- 연결 종료
- 작업이 끝나면 클라이언트는 DISCONNECT 커맨드를 전송하여 연결을 종료한다.
이와 같이 STOMP를 활용하면, Web Socket 상에서 데이터의 의미와 전달 방식을 명확히 정의할 수 있어, 복잡한 실시간 메시징 시스템을 보다 구조화된 방식으로 구현할 수 있다.
7. 결론
Web Socket과 STOMP는 현대의 실시간 통신 애플리케이션에서 매우 중요한 역할을 담당한다.
- Web Socket은 초기 핸드쉐이킹을 통해 HTTP 기반 연결을 Web Socket 연결로 전환하고, 이후 지속적인 프레임 기반 데이터 전송을 통해 낮은 오버헤드와 빠른 응답을 제공한다.
- STOMP는 이러한 Web Socket 위에서 메시지의 형식과 통신 규칙을 명확히 정의함으로써, 메시지 브로커와의 연동 및 Publish-Subscribe 패턴 구현을 용이하게 한다.
참조 : https://innu3368.tistory.com/213
https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API