WebSocket / STOMP / SockJS 를 활용한 채팅 정리

박세윤·2023년 6월 29일
1

📖 WebSocket / STOMP / SockJS 를 활용한 채팅 정리


📌 개념


✅ WebSocket

  • 웹에서 하나의 TCP 연결을 통해 양방향 통신을 제공하는 컴퓨터 통신 프로토콜

  • 실시간 서비스를 구현하기에 적합한 기술

  • 흔히 HTTP가 사용하는 Half-Duplex 방식이 아니라, 양방향인 Full-Duplex 방식이다.

    • Half-Duplex : 양방향 통신은 가능하지만, 동시에 송수신은 불가능하다.
    • Full-Duplex : 동시에 송수신이 가능하며, 양방향 통신이 가능하다.
  • 또한 일반 Socket 통신과 달리, HTTP 80 Port를 이용하여 방화벽에 제약 X

    • 접속까지는 HTTP 통신을 이용하고, 그 이후 통신은 WebSocket 프로토콜로 통신하는 방식을 많이 사용한다.



✅ STOMP (Simple Text Oriented Messaging Protocol)

  • 메세징 전송을 효율적으로 하기 위해 탄생한 프로토콜

  • 기본적인 WebSocket만을 사용한 통신에서는 발신자와 수신자를 Server단에서 직접 관리하고, WebSocketHandler를 만들어 클라이언트로부터 들어오는 메시지를 직접 다른 사용자에게 전달해줬어야 해서 단순 구현 코드가 복잡하고 길어진다.

  • 반면, STOMP는 pub/sub 기반으로 동작하여 메시지 송수신에 대한 처리를 @MessageMapping 등의 Annotation만으로 효율적으로 해결이 가능하다.

  • pub/sub 기반 동작 -> 메시지를 송신하고 수신하는 부분이 확실하게 구분되어 있어 개발자 입장에서 명확하게 인지하고 개발할 수 있다.

채팅방 생성 : Topic 생성

채팅방 입장 : 생성했던 Topic을 구독(sub) - 해당 채팅방을 WebSocket이 연결되어 있는동안 일종의 연결을 했다고 생각해보자.
연결이 되어 있기에 새로운 채팅이 송신(pub)되면 연결된 Topic으로 수신(구독, sub)을 하는 개념.



  • 메시지의 헤더에 값을 줄 수 있어 헤더 값을 기반으로 통신 시 인증 처리 가능
  • 서버는 메세지를 외부 Broker에게 전달하고, Broker는 WebSocket으로 연결된 클라이언트에게 메세지를 전달하는 구조.
    • 이와 같은 구조 덕분에 HTTP 기반의 보안 설정과 공통된 검증 등을 적용할 수 있게 된다.



✅ SockJS

  • WebSocket은 FireFox, Chrome, Edge, Whale 브라우저에서는 정상 작동 하지만, 모바일 Chrome이나 Internet Explorer에서는 동작하지 않는 이슈가 있다.

  • Server-Client 중간에 위치한 Proxy가 특정 Header를 인식 못한다거나, 임의로 Connection을 종료시킬 수도 있음.



  • 이러한 이슈들은 WebSocket Emulation 기술을 활용하여 해결할 수 있다.

  • WebSocket Emulation : 우선적으로 WebSocket을 활용하여 통신을 시도하고, 실패할 경우 HTTP 기반의 다른 기술로 전환하여 재연결을 시도하는 방식


  • 그리고 이 WebSocket Emulation 기술을 제공하는 JavaScript 라이브러리가 바로 SockJS이다.

  • SockJS는 어플리케이션이 WebSocket API를 사용하도록 허용하지만, 브라우저에서 WebSocket을 지원하지 않는 경우에 대안으로 어플리케이션의 코드를 변경할 필요 없이 런타임에 필요할 때 대체해준다.



📌 SpringBoot에서 WebSocket 서버 구축하기


✅ 의존성 추가

// gradle 형식

// WebSocket
implementation 'org.springframework.boot:spring-boot-starter-websocket'

// STOMP
implementation 'org.webjars:stomp-websocket:2.3.4'

// SockJS
implementation 'org.webjars:sockjs-client:1.5.1'



✅ WebSocket Config 설정

  • WebSocket을 활성화하기 위한 설정 파일

  • @EnableWebSocketMessageBroker : WebSocket 서버를 사용한다! 하는 설정 어노테이션

  • registerStompEndpoints : 클라이언트에서 websocket에 접속하는 endpoint를 등록

  • addEndpoint("/ws-stomp") : "/ws-stomp" 라는 엔드포인트(통신의 도착지점)를 설정 -> 웹 소켓 통신이 해당 엔드포인트에 도착하면 이 통신이 stomp 통신이구나! 하고 깨닫게 됨.

  • .withSockJS() : SocketJS를 사용하겠다!


  • configureMessageBroker 메서드 : 한 클라이언트에서 다른 클라이언트로 메시지를 라우팅 할 때 사용하는 브로커를 구성한다.

  • .enableSimpleBroker("/sub") : 메시지를 구독(수신)할 때 요청 URL

  • .setApplicationDestinationPrefixes("/pub") : 메시지 송신 요청 URL



✅ Controller에 사용되는 STOMP 어노테이션

  • @MessageMapping : STOMP에서 들어오는 Message를 서버에서 송신(pub)한 메시지가 도착하는 엔드포인트
    • 즉, 클라이언트가 메시지를 전송하면, @MessageMapping이 달린 메서드가 실행된다.


  • convertAndSend(메시지 도착지점, 메시지 객체) : 도착 지점으로 들어온 객체를 Message 객체 형식으로 변환하여 이 도착지점을 sub(구독)하고 있는 모든 사용자에게 메시지를 보내준다.
    • 그렇기에 한 채팅방에 여러명이 있더라도 하나의 Topic을 구독(sub)하고 있으니까 해당 채팅방의 모든 유저는 메시지를 읽을 수 있다.



✅ Socket.js - Front단

  • 지정했던 엔드포인트로 소켓 통신을 시작하고, 지속적으로 지정된 주소를 sub(구독) 및 지정된 주소에 pub(발송)

  • connect, onConnected, onError, sendMessage, onMessageReceived



  • Sockjs와 stomp client를 이용하여 Spring Boot에서 구성한 / ws 엔드 포인트에 연결



  • connect 함수에서 성공적으로 연결되었다면 콜백함수로 작성한 onConnected() 함수에서 동작합니다.



  • connect 함수에서 엔드포인트 연결을 실패했을 때 onError 함수 동작



  • JSON.stringify()를 통해 JSON 형식으로 메시지 전달



  • JSON.parse()를 통해 JSON 형식으로 받은 메시지를 다시 기존 타입으로 변환



profile
개발 공부!

0개의 댓글