스프링 웹소켓 및 STOMP

2024. 5. 19. 02:17카테고리 없음

 

 

[Spring Boot] STOMP를 이용한 실시간 채팅 및 채팅방 동적 생성

프로젝트 속 구현한 실시간 채팅은 다음과 같이 동작한다.STOMP(Simple Text Oriented Message Protocol)는 기존 WebSocket 통신 방식을 좀 더 효율적으로, 조금 더 쉽게 다룰 수 있게 해주는 프로토콜이다.이 프

velog.io

 

 

기존 http 통신은 서버가 클라이언트의 상태를 기억하지 않고 단방향으로 진행된다.

또한 연결이 오면 연결을 맺고 응답을 받으면 연결을 끊어버린다.  (요청단위로 통신)

 

웹소켓은 계속 연결을 유지하고 요청을 끝내는 동작이 따로 필요하다.

 

정보처리

http 와 웹소켓 통신은 주고받는 데이터 포멧이 다르다.

하지만 웹소켓 통신에서 핸드쉐이킹이 http 프로토콜 일어나긴 하지만 연결이 되고 여러 메세지를 주고받다보면

통신 비용이 절감될 수 있다.

 

웹소켓은 지원하지않는 브라우저가 존재함.

socketJS, socket.io 라이브러리를 통해 웹소켓을 지원하지않는 환경에서 비슷한 효과를 얻을 수 있음.(자바스크립트 라이브러리)

 

 

스프링 웹소켓

 

웹소켓 설정

1. 핸드쉐이킹할 경로와 이를 처리할 핸들러를 설정해야함.

(웹소켓 라이브러리는 텍스트와 바이너리 타입을 지원하고 필요에 따라  스프링에서 제공하는

기본 클래스(예시 : TextWebSocketHandler)를 상속받아 구현 받으면 됨)

 

주의할 점은 웹소켓은 세션을 컬랙션을 통해 관리하는데 이 세션은 우리가 아는 http 세션이 아니라 연결할때 생기는

연결 정보이다.

 

 cors 관련설정이나 라이브러리 관련 설정을 할 수 있다.

 

스프링 STOMP

 

스프링 웹소켓은 스프링 메세징을 제공한다.

이걸 이해하기 위해 STOMP를 이해해야한다,

 

STOMP는 이벤트 기반으로 쉽게 메시지를 주고받는 프로토콜이다.

 

발신자가 topic 으로 메세지로 전송

수신자는 topic 을 구독하고 발신자가 보낸 메시지를 받아볼 수 있음

메시지 브로커는 이러한 발행 구독을 가능할 수 있도록 중간에서 발신자가 보낸 메시지를 받아 수신자에게 전달하는 역할을 함.

 

stomp가 왜 필요하지?

웹소켓은 텍스트 혹은 바이너리만 지원한다.

추후 개발할때 주고 받는 형식을 정해야하는데 파싱하는 로직도 필요할것이고 부가적인게 많이 생길 수 있다.

 

STOMP는 프레임이라는 형식을 교환한다,

이는 커맨드 , 바디 , 헤더 형태로 이루어져있다.

 

통신 흐름

 

상황설명

- 구독자들은 topic A를 구독하고 있음.

- 발신자는 구독자들에게 메세지를 보내고 싶음.

 

방법 1

발신자가 topic A에 메세지를 바로 보냄 -> 브로커가 이를 받아 구독자들에게 메세지를 전달한다.

 

방법 2

발신자가 app에 메세지담아서 보냄

-> app 경로에 있는 핸들러가 메세지에 부가적인  행동(예로 이미지 압축)을 하고 정리해서 topic A로 보냄

-> 브로커가 이를 받아 구독자들에게 메세지를 전달한다.

 

STOMP 설정

1. 브로커가 어떤 경로로 가는 메세지 처리할건지 설정해야함.

- prefix를 지정하면 해당 prefix가 붙은 메시지는 브로커가 처리함

- 자주쓰이는 prefix : /queue  (1:1 통신 할 때) , /topic  (단체로 통신할 때)

2. 위의 방법2를 대비해 메세지 핸들러(부가적인 처리)로 라우팅할 prefix를 설정

- @Controller , @MessageMapping, @SendTo 를 통해 통신가능함

3. 핸드쉐이킹할 경로를 설정 (웹소켓과 다르게 따로 핸들러를 설정하지않음)

 

예시

상황 :  /app 을 메세지 핸들러(부가적인 처리)로 라우팅할 prefix를 설정

 

@Controller
public class GreetingController{

	@MessageMapping("hello")
	@SendTo("/topic/greeting")
	public Greeting greeting(HelloMessage message) throws Exception{
   		//HtmlUtils.htmlEscape 는 xss를 예방하기 위해 씀
		return new Greeting(
        	"Hello" + HtmlUtils.htmlEscape(message.getName()) + "!"
        );
	}
}

 

발신자가 /app/hello 에 메시지를 보내면 이름을 추출하고 hello를 붙어서 Greeting 객체로 만들어 /topic/greeting에 보냄.

그러면 브로커가 Greeting 객체를 /topic/greeting를 구독하는 구독자에게 메시지를 보내줌.

 

구독자가 특정 토픽을 구독하려는 로직

 

이부분은 클라이언트가 작성해야한다.

예시

상황 설명 : /add 가 핸드쉐이킹할 경로

1. /add 로 socket 객체를 만든다.

2. socket을 통해 클라이언트 객체를 만든다.

3. 클라이언트는 /topic/greeting 경로로 구독한다.