JAVA

Spring의 WebSocket

D_Helloper 2023. 6. 8. 21:44

WebSocket

  • 기존 단방향 HTTP 프로토콜과 호환되어 양방향 통신을 제공하기 위해 개발된 프로토콜
  • TCP/IP 레이어(4계층)를 사용하는 Socket과 달리 HTTP 레이어(7계층)에서 동작 80 포트를 사용하므로 방화벽에 제약이 없으며 WebSocket이라고 불림
  • HTTP 프로토콜을 사용하여 연결을 한 뒤, 자체적인 WebSocket 프로토콜을 활용하여 통신 진행
  • 실시간 양방향 통신을 위해 사용

HTTP와 WebSocket의 차이

출처 : https://kbj96.tistory.com/46

  • HTTP는 Response 이전에 Request가 반드시 존재해야 함
  • 하지만 이럴 경우, 채팅과 같은 경우에는 서버에 주기적으로 Request를 전송하여 메시지가 왔는지 확인해야 함 → 매우 비효율적
  • WebSocket은 양방향 통신이기 때문에 연결 이후에는 자유로이 통신 가능

Spring Websocket

  • 스프링에서 기본적으로 내장되어 있는 웹소켓

사용법

  • 의존성 추가(Gradle)
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-websocket'
}
  • WebSocket 엔드포인트 생성
@Component
@ServerEndpoint("/websocket")
public class MyWebSocketEndpoint {

    @OnOpen
    public void onOpen(Session session) {
        // 연결이 열릴 때 실행되는 로직
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        // 클라이언트로부터 메시지를 받을 때 실행되는 로직
    }

    @OnClose
    public void onClose(Session session) {
        // 연결이 닫힐 때 실행되는 로직
    }

    @OnError
    public void onError(Throwable error) {
        // 에러 발생 시 실행되는 로직
    }
}
  • WebSocket 구성
    • Spring의 구성 파일에서 WebSocket을 활성화 해야 함
    • @EnableWebSocket 어노테이션 사용하여 클래스를 만듦
    • registerWebScoketHandler() 메서드를 오버라이드하여 WebSocket 핸들러 등록
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Autowired
    private MyWebSocketEndpoint myWebSocketEndpoint;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(myWebSocketEndpoint, "/websocket")
                .setAllowedOrigins("*");
    }
}
  • 위에서 만든 MySwbSocketEndpoint 클래스를 Autowired를 통해 주입받음
  • WebSocketHandlerRegistry를 사용하여 WebSocket 핸들러 등록
  • 위 코드는 setAllowedOrigins(”*”); 를 통해 모든 origin으로부터의 요청을 허용하도록 되어 있음

STOMP(Simple Text Oriented Messaging Protocol)

  • Spring Framework에서 지원하는 메시징 프로토콜
  • 브로커, 목적지, 구독, 발행의 개념을 포함

Broker(브로커)

  • STOMP 메시지를 중계하고 클라이언트 간의 통신을 관리하는 중앙 시스템
  • STOMP Broker는 메시지를 발행(Publish)하고, 메시지를 구독(Subscribe)하는 클라이언트에게 메시지를 전달

Destination(목적지)

  • 메시지가 발행되거나 구독되는 대상 주제(topic)를 의미
  • 클라이언트는 특정 주제에 대한 구독 또는 발행 요청 가능

Subscribe(구독)

  • 클라이언트가 특정 주제(topic)에 대한 메시지를 수신하기 위해 구독 요청을 보내는 동작
  • 클라이언트는 특정 주제를 구독하면 해당 주제로 발행되는 메시지를 수신할 수 있음

Publish(발행)

  • 클라이언트가 특정 주제에 메시지를 발행하는 동작
  • 발행된 메시지는 해당 주제를 구독한 클라이언트에게 전달

사용법

  • 의존성 추가(Gradle)
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-websocket'
    implementation 'org.springframework.boot:spring-boot-starter-messaging'
}
  • WebSocket 엔드포인트 및 STOMP 핸들러 생성
    • 연결을 처리할 엔드포인트와 핸들러를 생성
    • 핸들러는 StompSessionHandlerAdapter를 상속받아 구현
    • 핸들러의 메시지를 수신하거나 전송하는 로직 구현
@Component
public class MyStompHandler extends StompSessionHandlerAdapter {

    @Override
    public void afterConnected(StompSession session, StompHeaders connectedHeaders) {
        // 연결이 성공한 후 실행되는 로직
    }

    @Override
    public void handleFrame(StompHeaders headers, Object payload) {
        // 클라이언트로부터 STOMP 메시지를 수신할 때 실행되는 로직
    }
}
  • WebSocket 구성
    • @EnableWebSocketMessageBroker 어노테이션을 사용하여 구성 클래스 생성
    • configureMessageBroker() 메서드를 오버라이드 하여 메시지 브로커 설정
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Autowired
    private MyStompHandler myStompHandler;

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic"); // 구독 대상 주제 설정
        registry.setApplicationDestinationPrefixes("/app"); // 클라이언트에서 메시지를 전송할 경로 설정
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/websocket") // WebSocket 엔드포인트 등록
                .setAllowedOrigins("*") // 모든 origin 허용 (보안 상황에 맞게 수정)
                .withSockJS(); // SockJS 지원 (브라우저의 WebSocket 지원 여부에 따라 자동 선택)
    }

    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.interceptors(new MyChannelInterceptor()); // 채널 인터셉터 등록 (선택 사항)
    }

    @Override
    public void configureClientOutboundChannel(ChannelRegistration registration) {
        registration.interceptors(new MyChannelInterceptor()); // 채널 인터셉터 등록 (선택 사항)
    }
}

Spring WebSocket과 STOMP 차이

Spring WebSocket

  • WebSocket 프로토콜을 기반으로 한 실시간 통신을 구현하기 위한 기술
  • 웹 브라우저와 서버 간의 양방향 통신을 지원하며, 실시간 데이터 전송이 필요한 애플리케이션에 적합
  • 간단한 API를 제공하며, 개발자는 직접 WebSocket을 처리하는 로직을 구현해야 함
  • WebSocket 연결을 설정하고, 클라이언트로부터 메시지를 수신하거나 메시지를 전송하는 등의 로직을 직접 구현해야 함

STOMP (Simple Text Oriented Messaging Protocol)

  • STOMP는 메시징 프로토콜로, WebSocket을 기반으로 한 실시간 통신을 더 쉽게 구현하기 위한 프로토콜
  • STOMP는 클라이언트와 서버 간의 메시지를 주고받기 위한 프레임워크
  • STOMP는 구독-발행 모델을 제공하여 클라이언트가 특정 주제에 대한 메시지를 구독하고, 서버는 해당 주제에 메시지를 발행할 수 있음
  • STOMP는 헤더, 몸체, 명령어 등의 구조로 메시지를 정의하고, 간단한 명령어를 사용하여 메시지를 전송
  • Spring에서는 STOMP를 사용하기 위해 spring-messaging 모듈을 제공하며, @MessageMapping 어노테이션과 같은 편리한 기능을 제공

STOMP가 Spring에서 기본적으로 제공하는 WebSocket보다 더 쉽고 간편하게 구조적으로 소켓을 구현할 수 있음