본문 바로가기
Language & Framework/Dart & Flutter

[Flutter] STOMP, WebSocket으로 실시간 통신하기

by 6cess 2024. 1. 15.

1. 개념

WebSocket 이란?

웹 애플리케이션에서 실시간 양방향 통신을 가능하게 하는 통신 프로토콜.

일반적으로 통신에 사용하는 HTTP 프로토콜은 요청해야 응답이 오는 방식으로 작동한다. 하지만 채팅, 실시간 업데이트와 같이 요청이 없어도 서버에서 지속적으로 응답을 주어야 하는 경우에는 HTTP 프로토콜을 사용하는 것에 불편함을 느끼게 된다.

이를 위해 고안된 것이 WebSocket 이다.

WebSocket 통신 프로세스

1) 클라이언트의 요청

 

클라이언트는 서버에 HTTP 요청을 보내고, 이 요청에는 WebSocket 연결을 원한다는 것을 나타내는 특별한 헤더가 포함된다.

 

2) 서버의 응답

 

서버가 WebSocket 연결을 지원하고 받아들일 준비가 되면,

클라이언트의 요청에 대해 101 Switching Protocols 상태 코드와 함께 응답한다.

이는 서버가 HTTP 프로토콜에서 WebSocket 프로토콜로 전환할 준비가 되었음을 나타낸다.

 

3) 프로토콜 전환

 

서버의 응답이 성공적으로 완료되면,

클라이언트와 서버 사이의 연결은 이제 WebSocket 프로토콜을 사용하여 데이터를 교환한다.

이 시점부터는 HTTP가 아닌 WebSocket 프로토콜이 사용되어 양방향 통신이 가능해진다.

STOMP (Simple Text Oriented Messaging Protocol) 란?

텍스트 기반 프로토콜.

매우 간단한 프로토콜이기 때문에 다양한 프로그래밍 언어와 환경에서 구현하고 사용하기 용이하다.

STOMP의 기본적인 통신 단위인 frame안에는

명령어(ex CONNECT, SUBSCRIBE, SEND)와 Headers, Body로 구성되어 있다.

 

- WebSocket과 STOMP에 대한 더 자세한 설명과 좋은 참고자료 소개하는 글

https://velog.io/@msung99/%EC%9B%B9%EC%86%8C%EC%BC%93%EC%9D%B4%EB%9E%80

 

웹소켓이란?

웹소켓(Web Socket), STOMP 란 뭘까? 기존 HTTP 프로토콜과 달리 실시간성을 보장해보자!

velog.io

 

2. stomp_dart_client 라이브러리 사용 방법

 

라이브러리 의존성 추가

 

dependencies:
  flutter:
    sdk: flutter
  stomp_dart_client: 원하는 버전
// 필요한 라이브러리 import
import 'package:stomp_dart_client/stomp.dart';
import 'package:stomp_dart_client/stomp_config.dart';
import 'package:stomp_dart_client/stomp_frame.dart';

 

STOMP 클라이언트 초기화

 

StompClient 객체를 초기화하면서 StompConfig를 통해 config를 설정한다.

class ChatService {

  var StompClient stompClient = StompClient(
      config: StompConfig(

        ... 


      ));
}

 

stompConfig 설정

 

class ChatService {

  var StompClient stompClient = StompClient(
      config: StompConfig(
        url: 'ws://your-websocket-server.com/chat',
        onConnect: // onConnect 콜백,
        onWebSocketError: (dynamic error) => print(error),
      ));

}

 

url 속성
말 그대로 websocket 서버 url을 입력하면 된다

 

onWebSocketError 속성
웹소켓 통신의 에러가 발생할 경우 호출되는 콜백을 설정한다

 

beforeConnect 속성

연결 초기화 직전에 실행할 콜백을 설정한다

일정 시간 딜레이를 넣어 연결 초기화에 필요한

비동기 작업을 기다리거나 연속 호출 등을 방지하는 등의 작업을 설정한다

 

onConnect 속성

서버와와 성공적으로 연결되었을 경우 호출되는 콜백을 설정한다
보통 onConnect 콜백 안에서 stompClient의 subscribe 메서드를 호출함으로써 연결 직후에 구독을 요청한다

 

StompClient의 구독 요청 및 취소

 

특정 destination을 구독하기 위해서는 StompClient가 제공하는 subscribe메서드를 실행한다.
보통 onConnect 속성으로 넘겨주는 콜백에서 실행한다.

class ChatService {

  var StompClient stompClient = StompClient(
      config: StompConfig(
        url: 'ws://your-websocket-server.com/chat',
        onConnect: (StompFrame frame) {
          stompClient.subscribe(
            destination: '/topic/your-topic',
            callback: (frame) {
              // 메시지 수신 시 수행할 작업
            },
          );
        },
        onWebSocketError: (dynamic error) => print(error),
      ));

}

 

반대로 구독을 취소하기 위해서는 stompClient.subscribe 호출 시 반환하는 함수를 사용해야 한다.
이를 위해 함수 타입의 변수를 선언하여 stompClient.subscribe 호출 시 리턴값을 담고 있도록 한다.

class ChatService {

  var StompClient stompClient = StompClient(
      config: StompConfig(
        url: 'ws://your-websocket-server.com/chat',
        onConnect: (StompFrame frame) {
          // subscribe메서드가 반환하는 함수 담기
          unsubscribeFunction = stompClient.subscribe(
            destination: '/topic/your-topic',
            callback: (frame) {
              // 메시지 수신 시 수행할 작업
            },
          );
        },
        onWebSocketError: (dynamic error) => print(error),
      ));

  Function? unsubscribeFunction;
}

 

나중에 구독을 취소할 때 unsubscribeFunction을 호출하면 된다.

if(unsubscribeFunction != null) {
  unsubscribeFunction();
}

 

StompClient 객체의 activate, send, deactivate

이제 선언한 stompClient 객체를 통해 activate 메서드로 클라이언트를 활성화하여 서버 연결을 시도한다.

 

activate 메서드 실행 후 send 메서드를 통해 메시지를 보낸다

if (stompClient != null || stompClient.connected != false) {
    stompClient.send(
        destination: "/chat/message",
        body: chat,
    );
}
 

이후 구독을 취소하려면 위의 unsubscribeFunction 메서드를 호출하고

 

아예 클라이언트를 비활성화하여 서버 연결을 종료하려면 deactivate메서드를 호출하면 된다.