Simple Text Oriented Messaging Protocol
텍스트 기반 메시징 프로토콜
웹소켓의 메시지 교환을 더 체계적으로 관리할 수 있도록 도와주는 프로토콜
메시지를 주고받는 표준적인 방법 제공
웹소켓(WebSocket) 위에서 동작
클라이언트-서버 간 메시지 형식 표준화
메시지 브로커 Pub/Sub(발행/구독) 패턴 지원
REST API와 비슷한 방식으로 메시지 라우팅 가능
| WebSocket | STOMP (WebSocket + STOMP) | |
|---|---|---|
| 메시지 포맷 | 바이너리 or 텍스트 (JSON 등) | STOMP 프레임 (헤더 + 바디) |
| 서버-클라이언트 메시지 라우팅 | 직접 구현해야 함 | endpoint 구조 지원 |
| Pub/Sub | 직접 구현해야 함 | 기본 지원 (다중 구독 지원) |
| 외부 메시지 브로커 | 직접 RabbitMQ 등과 연결 필요 | RabbitMQ, ActiveMQ 등과 쉽게 연동 |
| 자동 재연결 | 클라이언트가 직접 처리 | STOMP 라이브러리에서 지원 |
WebSocket + STOMP
@Configuration
@EnableWebSocketMessageBroker
class WebSocketConfig : WebSocketMessageBrokerConfigurer {
override fun registerStompEndpoints(registry: StompEndpointRegistry) {
registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS()
}
override fun configureMessageBroker(registry: MessageBrokerRegistry) {
registry.enableSimpleBroker("/topic", "/queue") // 구독 가능한 경로
registry.setApplicationDestinationPrefixes("/app") // 클라이언트가 서버로 보낼 때 붙이는 경로
}
}
일반 WebSocket
@Configuration
@EnableWebSocket
class WebSocketConfig : WebSocketConfigurer {
override fun registerWebSocketHandlers(registry: WebSocketHandlerRegistry) {
registry.addHandler(MyWebSocketHandler(), "/ws").setAllowedOrigins("*")
}
}
class MyWebSocketHandler : TextWebSocketHandler() {
override fun handleTextMessage(session: WebSocketSession, message: TextMessage) {
println("Received message: ${message.payload}")
session.sendMessage(TextMessage("Echo: ${message.payload}"))
}
}
오버헤드가 있음 (메시지 크기가 커짐)
WebSocket은 기본적으로 텍스트/바이너리 데이터만 주고받음
반면, STOMP는 프레임을 추가해야 하므로 데이터 크기가 더 커짐
→ 성능이 중요한 실시간 게임, 고속 데이터 스트리밍에는 부적합
메시지 브로커 사용 시 성능 이슈
내장 브로커(Simple Broker)는 가벼운 용도로 적합
대규모 트래픽 처리는 외부 메시지 브로커 추가 필요 (RabbitMQ, ActiveMQ)
→ 운영 부담이 늘어날 수 있음
STOMP 클라이언트가 필요함
WebSocket은 기본적으로 브라우저 API로 바로 사용 가능
하지만 STOMP는 stomp.js 같은 클라이언트 라이브러리를 추가해야 함
Spring WebSocket 의존성 필요
dependencies {
implementation("org.springframework.boot:spring-boot-starter-websocket")
}