WebSocket, Spring Websocket, STOMP, ChannelInterceptor

ㅎㅎ·2023년 5월 29일
0

WebSocket

목록 보기
1/1

웹소켓이란? 언제 사용?

  • 웹소켓의 배경

    • HTTP 프로토콜을 이용하여 URL을 요청 후 응답페이지 확인 → 실시간으로 Input하는 데이터에 따른 변화 불가능
    • → Ajax 통신을 이용하여 XML, JSON 등의 데이터 요청 → JavaScript가 응답받은 데이터를 DOM에 갱신하는 방식으로 변화
    • But 이 방법도 HTTP를 이용하기 때문에 Stateless함, 실시간 데이터 갱신을 위해서는 지속적인 요청-응답이 필요 → 자원 낭비
    • WebSocket을 통해 연결성 보장(Stateful)
  • 웹소켓이 필요한 경우: 체스 게임 어플처럼 상대의 말이 움직이는 것을 매번 실시간으로 갱신해주어야 할 때 → 요청-응답-연결해제가 아닌 요청-연결유지-지속적 응답 수신 구조인 WebSocket 사용

  • 웹소켓을 이용하지 않아도 실시간성 보장 가능한 방법 존재

    • Polling 기법 : 지속적으로 일정시간마다 요청을 보내서 페이지 갱신 → 자원낭비

HTTP와 웹소켓 차이

1.연결방식

  • http: stateless 연결 유지 X: http는 원하는 결과를 얻기 위해 새로 요청이 필요
  • 웹소켓: stateful? 연결 유지 → 매번 연결을 하기 위해 사용되는 비용 절감(3way handshake), 웹소켓은 연결이 되어 있기 때문에 상대방이 보내는 신호를 듣고 있으면 됨.

2.주고 받는 정보량의 차이

  • http: 요청과 응답 과정에서 주고 받는 데이터가 많은데 지속적으로 요청과 응답과정이 수행됨
  • 웹소켓: 한 번만 연결하기 때문에 주고받는 데이터량 적음, 한 번 연결되고나면 다음부터 간단한 메시지들만 오가기 때문에

웹소켓 in Spring

WebSocketConfig

  • Config 클래스 만들고
  • WebSocketConfigurer implements
  • @EnableWebSocket 어노테이션 붙임
  • 클라이언트가 보낸 메시지를 처리할 Handler가 필요 → SocketTextHandler()
  • path( ex→/user) → 웹소켓이 연결될 떄 handshake 할 주소
  • setAllowedOrigins(*) → SameOrigin만 허용하는 것이 기본정책 → Cors 허용 설정 변경 가능
  • withSockJs() → 웹소켓을 지원하지 않는 환경에서도 웹소켓 기능을 사용하기 위해 이 한 줄을 추가

WebSocketHandler

  • 필요에 따라 구현한 웹소켓 핸들러
  • 기본적으로 text와 binary type 지원 → TextWebSocketHandler나 BinaryWebSocketHandler 상속받아 구현하면 됨
  • 오버라이드한 메소드에서 인자로 받는 WebSocketSession : 웹소켓이 연결될 때 생기는 연결정보를 담고있는 객체
    • 핸들러에서 웹소켓 통신에 대한 처리를 하기 위해 이 세션들을 컬렉션으로 담아서 관리하는 경우가 많음(위 코드의 set)
    • 커넥션이 맺어어질 때 컬렉션에 웹소켓 세션을 추가하고 커넥션이 끊어지면 컬렉션에서 제거하도록 구현 → 이렇게 세션을 컬렉션으로 관리하면 모든 클라이언트에게 메시지를 보내는 기능을 구현 가능

STOMP and Spring-messaging?

스프링 웹소켓 디펜던시를 추가하면 STOMP와 Messaging도 딸려옴


S

  • pub-usb: 발신자가 경로로 메시지를 발행하면 구독하고 있는 수신자들은 그 메시지를 받아볼 수 있는 방식(메시지 송수신 방식)
  • 메시지 브로커: 발신자가 보낸 메신지를 받아서 수신자에게 받아주는 중개역할을 하는 구현체

왜 STOMP까지 사용해야 하지?

  • 웹소켓은 텍스트와 바이너리 타입의 메시지를 양방향으로 주고 받도록 정해진 프로토콜, 다만 어떤 형태로 메시지를 주고 받을지에 대해서는 정해진 것이 없음
  • 프로젝트가 커지고 다양한 기능에서 WebSocket을 사용하게 되면 각 기능마다 메시지를 주고 받는 로직이나 메시지의 형식이 제각각 → 기능에 따라서 WebSocket 구현이 달라지게 됨
  • STOMP가 정해놓은 위의 규칙을 이용하면 메시지 형식, 주고 받는 방식 등이 정해져있어 일관되게 사용하고 구현할 수 있음

  • STOMP 없이 소켓 사용(좌측): 단순 메시지만 송수신
  • STOMP 이용(우측): 어떤 구현 없이도 오른쪽과 같이 커맨드, 헤더, 바디 정보를 함께 송수신

메시지 통신 흐름

  • 만약 message에 대한 추가적인 처리가 필요하다면 /app 이라는 경로를 지정하여MessageHandler를 거치게 함, STOMP를 이용하면 이 Handler를 위의 WebSocketHandler처럼 따로 구현해줄 필요가 없이 간단하게 Controller 어노테이션과 MessageMapping 어노테이션을 이용하여 사용 가능함
    • app이라는 DestinationPrefixes를 지정해주지 않아도 소켓 세션에 연결된 사용자에게 그냥 message를 보낼 수가 있는듯, 하지만 기능마다 처리할 로직을 작성하고, 특정 채널에만 보내고자 할 때 Handler를 이용하여 발신주소와 수신주소를 특정할 수 있도록 하기 위함인듯.
  • app을 통해 들어온 메시지를 1차로 처리하고 구독자들에게 송신할 때 Spring의 내장된 SimpleBroker를 이용하여 최종적으로 다시 메시지를 수신자들에게 전달

WebSokcetMessageBrokerConfigurer(STOMP를 사용할 때 구현하는 Broker)

  • configureMessageBroker: MessageBroker를 설정하는 부분
  • registry.enableSimpleBroker → 스프링에서 제공하는 기본 브로커를 사용하겠다.
  • 파라미터 → 해당 값이 prefix로 붙은 메시지가 송신되었을 때그 메시지를 메시지브로커가 처리하겠다. 여기서는 queue, topic(queue는 메시지가 1대1로 처리될 때, topic은 1대 다로 처리될 때 사용하는 컨벤션)
  • setApplicationDestinationPrefixes → 바로 메시지를 보내는 것이 아니라 처리나 가공을 위해 Handler를 타는 경우(메시지 앞에 app이 붙어있는 경로로 발신되면 핸들러로 라우팅)

MessageHanlder(메시지에 대한 가공처리를 할 때 사용하는 핸들러)

  • STOMP를 사용하면 웹소켓만 사용했을 때 상속 받거나 했던 것과 달리 @Controller 를 사용해서 익숙한 방식으로 사용 가능
  • http 요청이 들어왔을 때 그 요청에 맞는 경로로 handler에게 처리를 위임해주듯이 STOMP 웹소켓 통신을 통해 메시지가 들어왔을 때 메시지의 DESTINATION HEADER와 메시지 매핑에 설정된 경로가 일치하는 핸들러를 찾고 그 핸들러가 처리
  • configuration에서 설정한 /app + /hello가 합쳐져서 들어온 메시지들이 처리되게 함
  • @ SendTo → 핸들러에서 처리를 마친 반환 값을 /topic/greeting이라는 경로로 돌려 보냄
  • 여기서는 처리를 마치고 반환된 Greeting 객체를 /topic을 관장하는 SimpleBroker로 보내게 됨

  • registerStompEndpoints → 웹소켓 코드의 addHandler 메소드와 비슷 → 인자로 들어가는 경로는 웹소켓의 ‘handshake’를 위한 주소 → Cors나 SockJs 설정도 가능 → 웹소켓 방식과 달리 STOMP를 사용하면 하나의 연결주소마다 handlerclass를 따로 구현하고 그것을 경로게 맞게 설정해줄 필요가 없이 Controller 방식으로 간편하게 사용 → STOMP를 스프링에서 사용하는 장점


ChannelInterceptor: 메시지를 주고 받으면서 메시지 전송과 관련한 추가 로직을 처리할 때 사용 ex) 메시지 암호화, 권한 검사 등

예시: StompCommand.CONNECT는 WebSocket 클라이언트가 서버에 연결하기 위해 보내는 STOMP CONNECT 프레임을 나타냄, CONNECT 프레임은 클라이언트가 서버에 연결 요청을 보내는 데 사용되며, 연결 매개변수와 헤더를 전달할 수 있음. CONNECT 프레임은 서버에 대한 인증 및 기타 설정과 관련된 정보를 전송하기 위해 사용될 수 있음

Reference:https://www.youtube.com/watch?v=rvss-_t6gzg

profile
Hello World

0개의 댓글