이제 서버에서 클라이언트에게 STOMP 연결을 할 수 있도록 핸드쉐이크 endpoint, messageBroker의 pub 및 sub prefix를 설정해 주어야 한다.
해당 설정은 스프링에서 설정하기에 매우 쉽다.
하지만 개념을 알아야 요구사항에 따른 구현이 가능하므로 일단 개념부터 잡아보자
1. Websocket
웹소켓 소개
- http는 tcp/ip 기반 비연결지향 프로토콜과 대비
- websocket 프로토콜(RFC6455) - 연결지향(연결을 끊지 않음), 양방향통신(클라이언트 <-> 서버)
- 서버와 클라이언트가 지속적으로 TCP 라인을 통해 연결되어 양방향 통신이 가능하게 됨
- 소켓이 유지되는데 동의할 수 있도록 소켓을 수정함
- http header의 keep-alive 속성의 값이 계속되도록 설정되어있음
- HTTP 와는 다른 TCP 프로토콜이지만 HTTP에서 동작가능하게 디자인 되었음
- 비동기식 이벤트 기반 메시징 아키텍쳐
- 거래소(주식, 암호화폐), 게임등 realtime이 보장되어야하는 상황에서 커넥션비용을 줄이고 불필요한 네트워크 비용을 감소시켜줌.
웹소켓 핸드쉐이크
- websocket 프로토콜에 의해 양쪽이 데이터를 해석하는 방법에 대한 합의를 해야 함
- 이를 위해 핸드쉐이크라는 과정을 거치게 됨
동작 과정
- 클라이언트가 서버로 HTTP UPGRADE 요청을 보냄
- 프로토콜 스위치가 일어나 웹서버의 웹소켓 서버로 전달받도록 설정함
- Sec-WebSocket-Key 와 Sec-WebSocket-Version, Upgrade: websocket 등의 헤더가 필요하다.
- Upgrade: websocket 헤더는 클라이언트가 연결을 다른 프로토콜로 업그레이드 할 것임을 나타내며, websocket으로 업그레이드 할 것임을 나타낸다
- 서버는 websocket이 열려있는 지 확인하기 위해 101 헤더로 응답함
- 서버는 클라이언트의 Sec-Websocket-Key 에 대해서 GUID 키를 붙여 sha1로 해슁한 값을 Sec-Websocket-Accept 헤더로 응답함
- Sec-Websocket-Extensions 값으로 클라이언트는 자신이 제공하는 확장 기능에 대해 알려줄 수 있음
- handshaking 요청에서 Sec-WebSocket-Protocol 을 사용하여 STOMP와 같은 높은 레벨의 메시징 프로토콜을 사용할 수 있음
2. SockJS
- 우선 WebSocket을 시도하고, upgrade 헤더요청에 실패할 경우 HTTP Streaming, Long-Polling 같은 HTTP 기반의 다른 기술로 전환하는 fallback 기술로, Websocket interaction을 에뮬레이트하고 같은 api를 노출하는 방식
- 이러한 기술을 쓰는 이유는 모든 브라우저가 웹소켓을 지원하지는 않기 때문이다
- Spring에서는 Servlet 스택에서 SockJS 프로토콜에 대한 서버 및 클라이언트를 모두 제공한다
WebSocket Emulation Process
- SockJS Client는 서버의 기본 정보를 얻기 위해 “GET /info”를 호출함
- /info 요청의 의미는 서버의 Websocket 지원 여부, Cookie 지원 여부 및 CORS 를 위한 Origin 정보를 응답받기 위함이다
- 응답받은 메시지를 토대로 앞으로 통신에 사용할 프로토콜을 결정함
- WebSocket 사용 가능하면 WebSocket 사용
- WebSocket 사용 불가능할 경우
- Options의 Transports 항목에 HTTP streaming 설정이 존재하면 HTTP streaming 사용
- Options의 Transports 항목에 HTTP Long Polling이 존재한다면, HTTP Long Polling 사용
- Optional 기능 사용시, 서버에 전송하는 요청 URL Schema
- https://host:port/myApp/myEndpoint/{server-id}/{session-id}/{transport}
- server-id : 클러스터에서 요청을 라우팅하는데 사용하나 이외에는 의미 없음
- session-id : SockJS session에 소속하는 HTTP 요청과 연관성 있음
- transport : 전송 타입 (예 : websocket, xhr-streaming, xhr-polling )
- WebSocket 사용 불가능할 경우
- WebSocket 사용 가능하면 WebSocket 사용
메시지 형식
- /info 요청 이후 핸드쉐이크가 성공할 경우 커넥션 유지를 위해 xhr?t 의 요청을 계속해서 보냄
- Message Frame 크기를 최소화하기 위해 노력함
- open frame (o) : 초기에 전송하는 메시지 프레임
- heartbeat frame (h) : 커넥션 유지 여부를 확인하는 heartbeat
- Array of json-encoded messages (a) : 메시지 프레임을 복수개로 전달받을 경우 사용됨
- 초기 연결시 전달받음
- ex). a["CONNECTED↵version:1.2↵heart-beat:0,0↵user-name:test2@naver.com"]
- close frame (c)
3. STOMP
- Streaming Text Oriented Message Protocol
- 토픽 구독방식
- pub/sub 구조로 되어있으며 브로커가 메시지를 받아 구독자에게 전송함
- Frame 기반 프로토콜
- 메시징 전송을 효율적으로 하기위한 websocket 위에서 동작하는 프로토콜
- 텍스트 기반이며 메시지큐의 동작을 프로토콜로 정의하여 사용됨
- 통신 메시지의 헤더에 값을 세팅할 수 있어 헤더 값 기반 통신시 인증처리 구현도 가능함
메시지 형식
SEND
destination:/queue/trade
content-type:application/json
content-length:44
{"action":"BUY","ticker":"MMM","shares",44}^@
MESSAGE
message-id:nxahklf6-1
subscription:sub-1
destination:/topic/price.stock.MMM
{"ticker":"MMM","price":129.45}^@
메시지 전체 흐름
- 스프링에서 메세지를 받음
- 외부 Broker에게 메시지 전달
- Websocket으로 연결된 구독자 Client에게 전달
- send한 메시지에 대해 handler를 붙여 처리 가능
출처 :
출처 : https://docs.spring.io/spring-fram
https://sjh836.tistory.com/166
https://docs.spring.io/spring/docs/4.3.18.RELEASE/spring-framework-reference/html/websocket.html https://d2.naver.com/helloworld/1336
https://docs.spring.io/spring-framework/docs/4.3.x/spring-framework-reference/html/websocket.html**
https://docs.google.com/presentation/d/1Y9q0rkgT9qIgjDXr_vILJUtlwmgc9Zj_BgNLBfyNBnU/edit?fbclid=IwAR2P0i4GnJbjVpF00WdBII6DDcYAI2vdIP7GUAFhZGqBmxRNF1WAtgUOCec#slide=id.g512074322f_0_915**
http://sockjs.github.io/sockjs-protocol/sockjs-protocol-0.3.3.html#section-26
'Spring > Spring Stomp' 카테고리의 다른 글
[Stomp] Spring Boot with React 채팅 서버 : 3-2. Stomp 기본 설정 (2) | 2022.03.14 |
---|---|
[Stomp] Spring Boot with React 채팅 서버 : 2. ChatRoomController (0) | 2022.03.02 |
[Stomp] Spring Boot with React 채팅 서버 : 1. Entity 디자인 (0) | 2022.03.02 |