괴발개발 공부하는 블로그

실시간 통신을 위한 websocket 과 STOMP 본문

프로젝트

실시간 통신을 위한 websocket 과 STOMP

ompeom 2023. 6. 8. 14:28

이번 사이드 프로젝트의 메인 주제는 미팅에서 사용할 수 있는 간단한 게임이다. 동시에 클라이언트에게 데이터를 전달할 수 있는 실시간 통신이 필요했다. 웹에서 어떻게 실시간 통신을 가능하게 할까? 찾아보니 websocket 을 사용하여 구현할 수 있었다.

 

이전 회사에서 윈도우 소켓 프로그래밍을 아주 잠깐 맛본 경험이 있었다. 그래서 대략적으로 어떤 플로우로 흘러가는 지 이해할 수 있었고, 조금 더 공부하기 위해 정리해보았다.

 

프로젝트의 기본적인 플로우

방장이 방을 개설한다. -> 유저들이 방으로 접속한다. -> 반복되는 부분 (방장이 이벤트(알림)을 보낸다. -> 유저들에게 실시간으로 알람이 간다. -> 유저들이 게임에 참여(응답) 한다.)

 

이게 기본적인 게임의 플로우이다. 이 흐름이 끊어지지 않게 실시간 통신이 필요하다.

 

실시간 통신 플로우 (websocket 과 http 프로토콜의 차이점)

websocket 과 http 통신은 둘 다 웹에서 데이터를 주고 받는 프로토콜이다.

핵심은 연결 상태 유지이다. 일반적으로 이해하고 있는 http 통신은 클라이언트 요청 -> 서버 응답 형식이다. 요청과 응답이 끝나면 바로 연결이 끊어진다. 그러나 websocket 통신의 경우 계속 연결을 유지한다.

 

  1. 통신 방식
    • http 는 클라이언트 - 서버 간의 요청 - 응답 방식으로 동작한다.
    • websocket 은 한 번의 연결 후 종료 전까지 데이터를 양방향으로 주고 받을 수 있다.
  2. 연결의 상태 유지
    • http 는 요청 및 응답 후 연결을 끊는다. 데이터를 주고받으려면 클라이언트가 새로운 http 요청을 보내야 한다. (풀 방식)
    • websocket 은 지속적으로 연결을 유지한다. 연결이 되어 있는 동안 언제든지 데이터를 주고받을 수 있다. (푸시 방식)
  3. 헤더 오버헤드
    • http의 요청 및 응답은 각각 헤더를 포함하고 있으며, 이러한 헤더들은 매 요청 및 응답마다 반복되어 헤더 오버헤드가 있을 수 있다.
    • websocket 은 초기 핸드쉐이크 요청 및 응답 시에 헤더를 포함하지만, 이 후에는 헤더 오버헤드가 적어 효율적인 양방향 통신이 가능하다.
  4. 용도
    • http 는 주로 클라이언트에서 서버로 웹 페이지, 이미지, 문서 등을 요청하고 응답받는 단방향이다.
    • websocket 은 주로 데이터 스트리밍, 채팅, 게임, 실시간 업데이트에 사용하는 실시간 양방향 통신이다.

 

websocket

웹 소켓은 http 로 연결 후 ws 이라는 프로토콜을 사용한다. 클라이언트 - 서버가 지속적인 연결을 유지하여 실시간으로 데이터를 양방향 전송 가능하다.

 

SockJS

양방향 통신에 대해서 검색을 하다보면 다들 SockJS 를 사용한다고 한다. 그래서 SockJS 가 정확히 무엇인지 정리해보았다.

 

SockJS 는 웹에서 실시간 양방향 통신을 구현하기 위한 JavaScript 라이브러리다. 웹 브라우저와 웹 서버 간 실시간 데이터를 전송하고 받을 때 사용한다. websocket 과 유사한 기능을 제공하지만 websocket 이 지원되지 않는 환경에서도 작동할 수 있도록 설계되었다.

처음에는 sockJS 에 대해 정확히 이해하지 못하였다. sockJS 는 자바스크립트 라이브러리인데 어떻게 java spring boot 환경에서 가능하다는 것인가? 에 대해서 의문을 가졌다.

 

SockJS 자체는 JavaScript 클라이언트 라이브러리이며, java 서버에서 직접 사용되는 것이 아니라 java 서버와 함께 사용하기 위한 클라이언트 - 서버 통신을 지원하는 라이브러리이다. java 서버에서는 websocket 과 같은 통신 프로토콜을 사용하여 SockJS 와 통신이 가능하다.

 

웹 브라우저 환경에서 서버와 양방향 통신을 구현할 때 사용된다. 이것은 java 와 함께 사용하기 위한 것이라기 보다는 웹 브라우저 - 서버 간의 통신을 단순화하고 통신 방법에 대해 추상화를 제공하는 것이다. 따라서 서버에서는 SockJS 를 직접 사용하는 것이 아니라 SockJS 와 호환되는 통신 방법을 제공해야 한다. 여기서 spring boot 에서 제공하는 websocket 의존성을 추가하여 확장할 수 있다.

 

STOMP

기본적으로 클라이언트 - 서버 간의 실시간 양방향 통신을 위해서는 websocket 을 사용한다. websocket은 단순히 양방향 통신을 제공하는 기술 자체를 이야기하며, 추가적인 메시지 전송과 관련한 기술은 직접 처리를 해야한다. (텍스트 데이터를 교환한다는 것 외에 어떠한 규격이나 정의가 없음)

따라서 websocket 을 사용하여 메시지를 전송하려면 클라이언트 - 서버 간의 약속된 데이터 형식과 프로토콜을 정의해야 한다.

 

STOMP 는 websocket 을 기반으로 동작하는 메시지 프로토콜로서 메시지의 전송을 구조화하고 규약화하여 개발자가 편리하게 사용할 수 있도록 한다. STOMP 는 헤더, 메시지 본문 등을 포함한 메시지 구조와 COMMAND 를 정의하여 전송하고 처리할 수 있다. 

 

따라서 websocket 만 사용한다면 개발자가 메시지에 전송에 대한 추가적인 작업을 해야하지만, STOMP 를 함께 사용한다면 표준화된 프로토콜을 활용하여 편리하게 작업이 가능하다.

 

STOMP 에는 구독(subscription)과 발행(publishing)이라는 개념이 존재한다.

websocket 을 통한 단순 텍스트 교환 방식과 달리 STOMP 프로토콜은 메세징 형식이 존재하고 구독과 발행 개념을 통해 메시지를 처리한다.

클라이언트가 특정 주소를 구독하고 있을 때, 발행자가 메시지를 전달하면 서버는 발행자의 메시지를 확인 후 같은 채널을 구독하는 모든 클라이언트에게 전달한다. 만약 클라이언트가 다른 url 을 구독하고 있다면 메시지를 전달받지 못한다.

 

카카오톡같은 메신저를 생각하면 쉽다. 카카오톡 같은 방에 참여하고 있다면 누군가 메시지를 보냈을 때, 그 방에 참여한 모든 사람이 메시지를 받는다. 다른 채팅방에는 메시지가 전달되지 않는다.

 

/queue /topic 을 붙이면 클라이언트가 메시지를 받을 때 경로를 설정해준다.

/app 을 붙이면 클라이언트가 메시지를 보낼 때 경로를 설정해준다.

 

websocket 개발 시 고려해야할 사항 - 웹 서버와 소켓 서버 분리의 필요성

웹 서버는 HTTP 요청 처리, 웹 소켓 서버는 실시간 양방향 통신이다. 웹 서버와 웹 소켓 서버의 주요 역할이 다르기 때문에 유지보수와 확장성 개선을 위해 분리해야 한다.

물론 웹 소켓은 비동기적인 특성을 가지고 있어서 일반적으로 스레드를 점유하지 않고, 비동기적으로 양방향 통신을 처리한다. 이로 인해 많은 연결을 동시에 처리할 수 있고 높은 효율성을 가진다. 그러나 서버의 자원보다 많은 클라이언트가 동시에 연결을 하게 되면 서버 연결 수가 증가하여 부하가 증가하고 응답 시간이 지연될 수 있다.

 

마무리

이번 사이드 프로젝트에서 websocket 실시간 통신이라는 것을 처음 공부하고 경험해보았다. 기본적인 개념조차 흔들리는 상태에서 냅다 구현하려니 너무 막막했다. websocket 이란 클라이언트와 서버가 실시간 양방향 통신을 하기 위한 하나의 프로토콜에 불과하다는 것을 이해하고 클라이언트에 어떤 데이터를 언제 보내주어야 할 지에 대해서만 고민하면 된다고 생각하니 훨씬 문제가 간단해졌다. (여기서 추상화에 대한 중요성을 한 번 더 깨달았다)

 

출처

https://ppaksang.tistory.com/18

https://docs.spring.io/spring-framework/reference/web/websocket/stomp/message-flow.html

https://brunch.co.kr/@springboot/695

Comments