STOMP (ํ”„๋กœํ† ์ฝœ)

STOMP๋ž€? (Simple Text Oriented Messaging Protocol)

STOMP๋Š” ๊ฐ„๋‹จํ•œ ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ ๋ฉ”์‹œ์ง• ํ”„๋กœํ† ์ฝœ์ด๋‹ค.

๋ฉ”์‹œ์ง• ๋ธŒ๋กœ์ปค๋ฅผ ํ™œ์šฉํ•ด์„œ pub/sub ๋ฐฉ์‹์œผ๋กœ Client-Server๊ฐ€ ์‰ฝ๊ฒŒ ๋ฉ”์‹œ์ง€๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ํ”„๋กœํ† ์ฝœ์ด๋‹ค.

  • ๋ฉ”์‹œ์ง€ ๋ธŒ๋กœ์ปค: ๋ฐœ์‹ ์ž์˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์•„์™€์„œ ์ˆ˜์‹ ์ž๋“ค์—๊ฒŒ ๋ฉ”์‹œ์ง€๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ

  • pub/sub: ๋ฐœ์‹ ์ž๊ฐ€ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐœํ–‰ํ•˜๋ฉด ์ˆ˜์‹ ์ž๋“ค์€ ๊ทธ๊ฒƒ์„ ์ˆ˜์‹ ํ•˜๋Š” ๋ฉ”์‹œ์ง• ํŒจ๋Ÿฌ๋‹ค์ž„

subscribe ๊ณผ์ •

๋”ฐ๋ผ์„œ STOMP๋Š” WebSocket ์œ„์— ์–น์–ด์„œ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ•˜์œ„(์„œ๋ธŒ) ํ”„๋กœํ† ์ฝœ์ด๋‹ค.

STOMP๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ? ์žฅ์ ?

WebSocket ํ”„๋กœํ† ์ฝœ์€ ๋‘ ๊ฐ€์ง€ ์œ ํ˜•์˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ •์˜ํ•œ๋‹ค.

  1. Text Frame: UTF-8๋กœ ์ธ์ฝ”๋”ฉ๋œ ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•˜๋Š” ๋ฉ”์‹œ์ง€์ด๋‹ค. ์ฃผ๋กœ ๋ฌธ์ž์—ด ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.

  2. Binary Frame: ๋ฐ”์ด๋„ˆ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•˜๋Š” ๋ฉ”์‹œ์ง€๋กœ ์ด๋ฏธ์ง€, ๋น„๋””์˜ค, ํŒŒ์ผ ๋“ฑ ํ…์ŠคํŠธ๊ฐ€ ์•„๋‹Œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.

์ด๋ ‡๊ฒŒ ๋‘ ๊ฐ€์ง€ ์œ ํ˜•์˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ •์˜ํ•˜๊ณ  ์žˆ์ง€๋งŒ, ๋ฉ”์‹œ์ง€์˜ ํ˜•์‹์ด๋‚˜ ๊ตฌ์กฐ์— ๋Œ€ํ•œ ๊ตฌ์ฒด์ ์ธ ๊ทœ์ •์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค.

๋”ฐ๋ผ์„œ ๋ฉ”์‹œ์ง€๋ฅผ ์–ด๋–ค ํ˜•์‹์œผ๋กœ ์ฃผ๊ณ ๋ฐ›์„ ์ง€ ์ •ํ•ด์ง„๊ฒŒ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ง์ ‘ ๋ณ„๋„์˜ ๊ตฌํ˜„์ด ํ•„์š”ํ•˜๋‹ค.

  • ๋ฉ”์‹œ์ง€ ํ˜•์‹ ์ •์˜ (= ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๋Š” ๋ฉ”์‹œ์ง€ ํฌ๋งท ์ •์˜), ex) json, xml ..

  • ๋ฉ”์‹œ์ง• ํŒจํ„ด ๊ตฌํ˜„ (pub/sub ๊ฐ™์€ ๋ฉ”์‹œ์ง• ํŒจํ„ด์ด๋‚˜, ๋ผ์šฐํŒ…์„ ๊ด€๋ฆฌํ•˜๋Š” ๋กœ์ง ๋“ฑ)

  • ์—ฐ๊ฒฐ ๋ฐ ์„ธ์…˜ ๊ด€๋ฆฌ (์„ธ์…˜ ๊ด€๋ฆฌ๋‚˜ ์ƒํƒœ ์œ ์ง€๋ฅผ ์œ„ํ•œ ์ถ”๊ฐ€์ ์ธ ๊ตฌํ˜„์ด ํ•„์š”)

๊ฐœ๋ฐœ์ž๋Š” Client-Server๊ฐ€ ์–ด๋– ํ•œ ํ˜•์‹์œผ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ์ฃผ๊ณ  ๋ฐ›์„์ง€ ์ •์˜ํ•˜๊ณ  ํŒŒ์‹ฑํ•˜๋Š” ๋กœ์ง์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.

์ฆ‰ WebSocket ํ”„๋กœํ† ์ฝœ๋งŒ ์‚ฌ์šฉํ•ด์„œ ์†Œ์ผ“ ์„œ๋ฒ„๋ฅผ ๊ตฌ์„ฑํ•œ๋‹ค๋ฉด ํ•ด๋‹น ๋ฉ”์‹œ์ง€๊ฐ€ ์–ด๋–ค ์š”์ฒญ์ธ์ง€, ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š”์ง€์— ๋”ฐ๋ผ์„œ ์ฑ„ํŒ…๋ฐฉ๊ณผ ์„ธ์…˜์„ ์ผ์ผ์ด ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๊ณ  ๋ฉ”์‹œ์ง€ ๋ฐœ์†ก์„ ๊ด€๋ฆฌํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.

STOMP๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด๋Ÿฌํ•œ ํ˜•์‹, ํŒŒ์‹ฑ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•„๋„ ๋˜๊ณ , ๊ธฐ๋ณธ์ ์œผ๋กœ pub/sub ๊ตฌ์กฐ๋กœ ๋˜์–ด์žˆ์–ด์„œ ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†กํ•˜๊ณ  ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ถ€๋ถ„์ด ์ •ํ•ด์ ธ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ตฌํ˜„์˜ ๋ณต์žก์„ฑ์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

STOMP๋Š” WebSocket ์œ„์—์„œ ๋™์ž‘ํ•˜๋ฉฐ, ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„๊ฐ€ ์ „์†กํ•  ๋ฉ”์‹œ์ง€์˜ ์œ ํ˜•, ํ˜•์‹, ๋‚ด์šฉ๋“ค์„ ์ •์˜ํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด๋‹ค.

  • Frame์ด๋ผ๊ณ  ํ•ด์„œ "Command, body, Header"๋กœ ๊ทธ ํ˜•์‹์„ ์ด๋ฏธ ์ •ํ•ด๋‘์—ˆ๋‹ค.

์ด๋Ÿฐ ์‹์œผ๋กœ ๋ฉ”์‹œ์ง€์˜ ํ—ค๋”์— ๊ฐ’์„ ์ค„ ์ˆ˜ ์žˆ์–ด์„œ ํ—ค๋” ๊ฐ’์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ†ต์‹  ์‹œ ์ธ์ฆ ์ฒ˜๋ฆฌ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋ฉฐ STOMP ์ŠคํŽ™์— ์ •์˜ํ•œ ๊ทœ์น™์„ ์ง€ํ‚ค๋ฉด์„œ ์—ฌ๋Ÿฌ ์–ธ์–ด ๋ฐ ํ”Œ๋žซํผ ๊ฐ„ ๋ฉ”์‹œ์ง€๋ฅผ ์ƒํ˜ธ ์šด์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

STOMP์˜ Frame

STOMP๋Š” TCP ๋˜๋Š” WebSocket๊ณผ ๊ฐ™์€ ์–‘๋ฐฉํ–ฅ ๋„คํŠธ์›Œํฌ ํ”„๋กœํ† ์ฝœ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

HTTP์—์„œ ๋ชจ๋ธ๋ง๋˜๋Š” Frame ๊ธฐ๋ฐ˜ ํ”„๋กœํ† ์ฝœ์ด๋ฉฐ, Frame์€ ๋ช‡ ๊ฐœ์˜ Text Line์œผ๋กœ ์ง€์ •๋œ ๊ตฌ์กฐ์ด๋‹ค.

์ฒซ ๋ฒˆ์งธ ๋ผ์ธ์€ Text์ด๋‹ค.

  • SEND, SUBSCRIBE, UNSUBSCRIBE, ACK ๋“ฑ์˜ ๋ช…๋ น์–ด๊ฐ€ ์žˆ๋‹ค.

์ดํ›„์— ๋“ฑ์žฅํ•˜๋Š” ๋ผ์ธ์€ Key:Value ํ˜•ํƒœ๋กœ Header์˜ ์ •๋ณด๋ฅผ ํฌํ•จํ•œ๋‹ค. (์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ—ค๋” ์กด์žฌ ๊ฐ€๋Šฅ)

  • destination, content-type, subscription ๋“ฑ์ด ์žˆ๋‹ค.

ํ—ค๋” ๋‹ค์Œ์œผ๋กœ๋Š” ๋นˆ ๋ผ์ธ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ค์ œ ๋ฐ์ดํ„ฐ๊ฐ€ ํฌํ•จ๋˜๋Š” ๋ณธ๋ฌธ(Body, Payload)๊ฐ€ ์กด์žฌํ•œ๋‹ค.

์ด ๊ตฌ์กฐ๋Š” HTTP ์š”์ฒญ ํ˜•์‹๊ณผ ๋งค์šฐ ์œ ์‚ฌํ•˜๋‹ค.

Command: SEND, SUBSCRIBE๋ฅผ ์ง€์‹œํ•  ์ˆ˜ ์žˆ๋‹ค.

Header: ๊ธฐ์กด์˜ WebSocket์œผ๋กœ๋Š” ํ‘œํ˜„์ด ๋ถˆ๊ฐ€๋Šฅ ํ–ˆ์—ˆ๋˜ header๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

destination: ์ด ํ—ค๋”๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๊ฑฐ๋‚˜ ๊ตฌ๋… ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • destination์€ ์˜๋„์ ์œผ๋กœ ์ •๋ณด๋ฅด๋ฅด ๋ถˆ๋ถ„๋ช…ํ•˜๊ฒŒ ์ •์˜ํ–ˆ๋Š”๋ฐ, ์ด๋Š” STOMP ๊ตฌํ˜„์ฒด์—์„œ ๋ฌธ์ž์—ด ๊ตฌ๋ฌธ์— ๋”ฐ๋ผ ์ง์ ‘ ์˜๋ฏธ๋ฅผ ๋ถ€์—ฌํ•˜๋„๋ก ํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค. ๋”ฐ๋ผ์„œ destination ์ •๋ณด๋Š” STOMP ์„œ๋ฒ„ ๊ตฌํ˜„์ฒด๋งˆ๋‹ค ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ ์œ„ ํ˜•์‹์„ ๋”ฐ๋ฅธ๋‹ค.

ํด๋ผ์ด์–ธํŠธ B์—์„œ ์ฑ„ํŒ…์„ ๋ณด๋‚ด๋Š” ์˜ˆ์‹œ์ด๋‹ค.

STOMP๋Š” ๋ชจ๋“  ๊ตฌ๋…์ž์—๊ฒŒ ๋ฉ”์‹œ์ง€๋ฅผ ๋ธŒ๋กœ๋“œ์บ์ŠคํŠธ ํ•˜๊ธฐ ์œ„ํ•ด MESSAGE COMMAND๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์„œ๋ฒ„๋Š” ๋‚ด์šฉ(roomId)๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†กํ•  Broker์—๊ฒŒ ์ „๋‹ฌํ•œ๋‹ค.

Spring์ด STOMP๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋™์ž‘ ํ๋ฆ„

  1. ๋ฐœ์‹ ์ž๋Š” ๊ตฌ๋…์ž์—๊ฒŒ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๋ ค๊ณ  ํ•œ๋‹ค. ๊ตฌ๋…์ž๋“ค์€ "/topic"์ด๋ผ๋Š” ๊ฒฝ๋กœ๋ฅผ ๊ตฌ๋…ํ•˜๊ณ  ์žˆ๋‹ค.

  2. ๋ฐœ์‹ ์ž๋Š” endpoint์— "/topic"์„ ๋„ฃ์–ด์„œ ๋ฐ”๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์ง€๋งŒ, "/app"์ด๋ผ๋Š” endpoint๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ์†ก์‹ ํ•ด์„œ ์„œ๋ฒ„ ๋‚ด์—์„œ ๋ฉ”์‹œ์ง€๋ฅผ ๊ฐ€๊ณต, ์ฒ˜๋ฆฌ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฐ€๊ณตํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉด ๋ธŒ๋กœ์ปค๋ฅผ ํ†ตํ•ด ๋ฐ”๋กœ ๋ณด๋‚ด๋„ ๋œ๋‹ค.

  3. ์„œ๋ฒ„๊ฐ€ ๊ฐ€๊ณต์„ ๋งˆ์น˜๋ฉด "/topic"์ด๋ผ๋Š” ๊ฒฝ๋กœ์— ๋‹ด์œผ๋ฉด ๋ฉ”์‹œ์ง€๋Š” ๋ธŒ๋กœ์ปค์—๊ฒŒ ์ „๋‹ฌ๋˜๊ณ , ๋ฉ”์‹œ์ง€ ๋ธŒ๋กœ์ปค๋Š” "/topic"์„ ๊ตฌ๋…ํ•œ ๊ตฌ๋…์ž์—๊ฒŒ ๋ฉ”์‹œ์ง€๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.

Last updated