[๐ŸŒผSpring] Websocket์˜ ๋“ฑ์žฅ ๋ฐฐ๊ฒฝ, ๋™์ž‘ ๋ฐฉ์‹, ํ•œ๊ณ„์  (+ HTTP Poling, SSE ๋น„๊ต)

ํ•˜๋ฆฌ๋น„ยท2025๋…„ 6์›” 24์ผ
3

๐ŸŒผ Spring

๋ชฉ๋ก ๋ณด๊ธฐ
11/11

๐Ÿ™‹๐Ÿปโ€โ™€๏ธ์•ผ๊ตฌ ์‹ค์‹œ๊ฐ„ ์†Œํ†ต ํ”Œ๋žซํผ์˜ ๋ผ์ด๋ธŒ ์ฑ„ํŒ… ๊ธฐ๋Šฅ ๊ตฌํ˜„ ์ค‘,
websocket + stomp๋ฅผ ์‚ฌ์šฉํ•ด ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ…๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ–ˆ๋‹ค.
์‹ค์‹œ๊ฐ„ ํ†ต์‹ ์„ ์œ„ํ•œ
1. websocket ๋“ฑ์žฅ ์ด์ „์˜ ๋ฐฉ์‹ 2. ๋‹จ๋ฐฉํ–ฅ ํ†ต์‹ (SSE) 3. ์–‘๋ฐฉํ–ฅ ํ†ต์‹ (Websocket) ์— ๋Œ€ํ•ด ์ •๋ฆฌํ–ˆ๋‹ค


๊ธฐ์กด์˜ Http ํ†ต์‹ ์€
ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„์—๊ฒŒ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ , ์‘๋‹ต์„ ๋ฐ›๋Š” HTTP ๊ธฐ๋ฐ˜ ๋‹จ๋ฐฉํ–ฅ ํ†ต์‹ ์ด๋‹ค

๐Ÿšซํ•œ๊ณ„ : HTTP ํ†ต์‹ ์˜ Stateless, Connectionlessํ•œ ํŠน์„ฑ

์˜ˆ๋ฅผ ๋“ค์–ด, ๋‚ด๊ฐ€ ์ง€๊ธˆ ๊ตฌํ˜„ํ•˜๊ณ ์ž ํ•˜๋Š” ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ…์˜ ๊ฒฝ์šฐ,
์ฑ„ํŒ…๋ฐฉ์— ์ฐธ์—ฌ์ค‘์ธ ๋ชจ๋“  ์ƒ๋Œ€๋ฐฉ์˜ ๋ฉ”์„ธ์ง€๋ฅผ ๋ฐ›๊ธฐ์œ„ํ•ด์„œ๋Š” ๋งค๋ฒˆ ์š”์ฒญ์„ ๋ณด๋‚ด์•ผํ•จ

๋‚ด๊ฐ€ ๋จผ์ € ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋‚ผ ์ˆœ ์žˆ์ง€๋งŒ, ์„œ๋ฒ„๋Š” ์„ ํ†ก์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค..^^
์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ Http ์—์„œ์˜ ๊ธฐ์ˆ ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค



๐Ÿ“– HTTP Polling

๐Ÿ“Œ Polling

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ผ์ • ์ฃผ๊ธฐ๋กœ http request๋ฅผ ๋ณด๋‚ธ๋‹ค

๐Ÿšซ ๋‹จ์ 

  • HTTP ์˜ค๋ฒ„ํ—ค๋“œ ๋ฐœ์ƒ : ๋ถˆํ•„์š”ํ•œ ์š”์ฒญ ๅคš
  • ์ปค๋„ฅ์…˜ ๋งบ์„ ๋•Œ๋งˆ๋‹ค ๋น„์šฉ ๋ฐœ์ƒ
  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋งŽ์•„์งˆ ๋•Œ๋งˆ๋‹ค ์„œ๋ฒ„์˜ ๋ถ€๋‹ด โ†‘

๐Ÿ“Œ Long Polling

ํด๋ผ์ด์–ธํŠธ์˜ request๋ฅผ ์„œ๋ฒ„๋Š” ์ผ์ •์‹œ๊ฐ„ ๋Œ€๊ธฐ ํ›„ ์‘๋‹ต์„ ์ค€๋‹ค
์‘๋‹ต๊นŒ์ง€์˜ ์‹œ๊ฐ„์„ ์ตœ๋Œ€ํ•œ ๋Š˜๋ ค์„œ ์ด๋ฒคํŠธ ๋ฐœ์ƒ์‹œ๊นŒ์ง€ ๋Œ€๊ธฐํ•œ๋‹ค

1. ํด๋ผ์ด์–ธํŠธ์—์„œ ์„œ๋ฒ„๋กœ http request๋ฅผ ๋ณด๋‚ด๋ฉด
2. ์„œ๋ฒ„๋Š” ์—ฐ๊ฒฐ์„ ์•ˆ๋Š๊ณ  ๊ธฐ๋‹ค๋ฆผ
3. ์ด๋ฒคํŠธ ๋ฐœ์ƒ์‹œ ์„œ๋ฒ„๋Š” ์‘๋‹ต์„ ์ฃผ๊ณ  ์—ฐ๊ฒฐ ์ข…๋ฃŒ
4. ํด๋ผ์ด์–ธํŠธ๋Š” 3๋ฒˆ์—์„œ ์‘๋‹ต์„ ๋ฐ›๊ณ  ๋‹ค์‹œ ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค

๐Ÿšซ ๋‹จ์ 

  • ๋ฐ์ดํ„ฐ๊ฐ€ ๋Œ€๊ธฐ์‹œ๊ฐ„์— ๋น„ํ•ด ๋ณ€ํ™”๊ฐ€ ์žฆ์„ ๊ฒฝ์šฐ, ์ผ๋ฐ˜ polling๋ณด๋‹ค <์š”์ฒญ-์‘๋‹ต>์ด ๋งŽ์•„์ง
  • ๋‹ค์ˆ˜์˜ ํด๋ผ์ด์–ธํŠธ์— ๋™์‹œ ์ด๋ฒคํŠธ ๋ฐœ์ƒ์‹œ, ์‘๋‹ต ๋ฐ›์€ ํ›„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋™์‹œ์— ์š”์ฒญ์„ ๋ณด๋‚ด๋ฏ€๋กœ ์„œ๋ฒ„ ๋ถ€๋‹ด ๊ธ‰์ฆ


๐Ÿ“– SSE(Server Sent Event)


์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๋Š” ๊ธฐ์ˆ ์ด๋‹ค
๊ธฐ๋ณธ์ ์œผ๋กœ HTTP ์—ฐ๊ฒฐ์„ ๊ธธ๊ฒŒ ์œ ์ง€ํ•˜๋ฉด์„œ ์„œ๋ฒ„ โž ํด๋ผ์ด์–ธํŠธ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•œ๋‹ค

polling ์ดํ›„๋กœ ๋“ฑ์žฅํ•œ ๊ธฐ์ˆ ๋กœ HTTPํ†ต์‹ ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‹จ๋ฐฉํ–ฅ ํ†ต์‹  ๊ธฐ์ˆ ์ด๋‹ค
์ฃผ๋กœ ์„œ๋ฒ„์˜ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์ด ์žˆ์„๋•Œ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์•Œ๋ ค์ฃผ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค

โœ… ๋™์ž‘ ๋ฐฉ์‹

1. Client : SSE Subscribe ์š”์ฒญ

GET /connect HTTP/1.1
Accept: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

ํด๋ผ์ด์–ธํŠธ - EventSource ๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋กœ SSE ์—ฐ๊ฒฐ ์š”์ฒญ์„ ํ•œ๋‹ค

2. Server: Subscription์— ๋Œ€ํ•œ ์‘๋‹ต

HTTP/1.1 200
Content-Type: text/event-stream;charset=UTF-8
Transfer-Encoding: chunked

์„œ๋ฒ„ - SseEmitter ๋ฅผ ์ด์šฉํ•ด ๊ตฌ๋… ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์„ ํ•œ๋‹ค

3. Server: ์ด๋ฒคํŠธ ์ „๋‹ฌ

  • ์„œ๋ฒ„๊ฐ€ ์ด๋ฒคํŠธ ์ŠคํŠธ๋ฆผ์„ ์ „์†กํ•˜์—ฌ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์—…๋ฐ์ดํŠธ๋œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•œ๋‹ค
  • ๋ฐ์ดํ„ฐ๋Š” UTF-8๋กœ ์ธ์ฝ”๋”ฉ๋œ ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ๋งŒ ๊ฐ€๋Šฅ(๋ฐ”์ด๋„ˆ๋ฆฌ ๋ฐ์ดํ„ฐโŒ)

๐Ÿ” ๋ฐ์ดํ„ฐ ํ˜•์‹ - name:value

event: type1
data: An event of type1.

event: type2
data: An event of type2.

๐Ÿ“Œ ์žฅ๋‹จ์ 

โญ•๏ธ ์žฅ์ 

  • HTTP ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜๊ธฐ์— ๊ตฌํ˜„์ด ๋น„๊ต์  ๊ฐ„๋‹จํ•˜๋‹ค
    (ํŠน๋ณ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ/์ถ”๊ฐ€์„ค์ • ์—†์ด๋„ ์‚ฌ์šฉ๊ฐ€๋Šฅ)
  • ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ด๋ฒคํŠธ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์šฉ์ดํ•˜๋‹ค
  • ๋„คํŠธ์›Œํฌ ๋‹จ์ ˆ์‹œ EventSource๊ฐ€ ์ž๋™์œผ๋กœ ์žฌ์—ฐ๊ฒฐ์„ ์‹œ๋„ํ•จ

โŒ ๋‹จ์ 

  • payload์˜ ํฌ๊ธฐ๊ฐ€ ์ œํ•œ์ ์ด๋‹ค
  • ๋ธŒ๋ผ์šฐ์ € ํ˜ธํ™˜์„ฑ
  • ๋‹จ๋ฐฉํ–ฅ ํ†ต์‹ ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค


๐Ÿ“– Websocket


WebSocket์€ ๊ธฐ๋ณธ HTTP ํ•ธ๋“œ์…ฐ์ดํฌ๋ฅผ ํ†ตํ•ด ์—ฐ๊ฒฐ์„ ์‹œ์ž‘ํ•˜๊ณ ,
์ดํ›„์—๋Š” ์ง€์†์ ์ธ TCP ์—ฐ๊ฒฐ์„ ํ†ตํ•ด ์–‘๋ฐฉํ–ฅ ํ†ต์‹ ์ด ๊ฐ€๋Šฅํ•œ ํ”„๋กœํ† ์ฝœ์ด๋‹ค

๐Ÿ” TCP = ์—ฐ๊ฒฐ์ง€ํ–ฅ ํ”„๋กœํ† ์ฝœ (http์˜ connectionless์™€ ๋Œ€๋น„๋จ)

โœ… ๋™์ž‘ ๋ฐฉ์‹

Websocket์˜ ๋™์ž‘์€ 1๏ธโƒฃ handshake , 2๏ธโƒฃ Data transfer, 3๏ธโƒฃ Close Handshake ์˜ ๊ณผ์ •์„ ๊ฑฐ์นœ๋‹ค
๊ณผ์ • ๋ณ„๋กœ ์ž์„ธํžˆ ์‚ดํŽด๋ณด์ž !


๐Ÿ“Œ โถ Handshake

  • ์ฒ˜์Œ ์—ฐ๊ฒฐ ์‹œ์—๋Š” HTTP ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค GET
  • ์ดํ›„ ์‘๋‹ต์ด 101 Switching Protocols๋ฉด WebSocket ์—ฐ๊ฒฐ ์„ฑ๊ณต!
  • ๐Ÿ” port
    • ws://์˜ ๊ธฐ๋ณธ ํฌํŠธ๋Š” 80
    • wss://์˜ ๊ธฐ๋ณธ ํฌํŠธ๋Š” 443

โœ”๏ธ Request ์˜ˆ์‹œ

GET /ws-endpoint HTTP/1.1 
Host: server.example.com 
Upgrade: websocket ---------------------------> โœ… ์›น์†Œ์ผ“ ํ”„๋กœํ† ์ฝœ๋กœ ๋ณ€๊ฒฝํ• ๋ž˜
Connection: Upgrade ---------------------------> โœ… Upgrade ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== 
Origin: http://example. com 
Sec-WebSocket-Protocol: chat, superchat ---------------------------> โœ… ์„œ๋ธŒ ํ”„๋กœํ† ์ฝœ
Sec-WebSocket-Version: 13 

โœ… Upgrade, Connection ํ—ค๋” โ†’ ์›น์†Œ์ผ“ ์ „ํ™˜ ์š”์ฒญ์ž„์„ ํ‘œ์‹œ
โœ… Sec-WebSocket-Key โ†’ ์„œ๋ฒ„๊ฐ€ ์ธ์ฆ์„ ์œ„ํ•ด ํ™•์ธํ•˜๋Š” ๊ฐ’


โœ”๏ธ Response ์˜ˆ์‹œ

HTTP/1.1 101 Switching Protocols -------------------> โœ… ์›น์†Œ์ผ“ ์—ฐ๊ฒฐ ์„ฑ๊ณต (101)
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
  • ์›น์†Œ์ผ“ ์—ฐ๊ฒฐ ์„ฑ๊ณต์€ ์ƒํƒœ์ฝ”๋“œ 101 (๊ทธ ์™ธ์˜ ์ฝ”๋“œ ์‘๋‹ต์‹œ http ํ†ต์‹  ์œ ์ง€)
  • Sec-WebSocket-Accept ์ž‘๋™ ๋ฐฉ์‹
    • ์„œ๋ฒ„๋Š” Sec-WebSocket-Key์— ๊ณ ์ • ๋ฌธ์ž์—ด258EAFA5-E914-47DA-95CA-C5AB0DC85B11์„ ๋ถ™์ด๊ณ 
    • SHA-1 ํ•ด์‹œ โ†’ Base64 ์ธ์ฝ”๋”ฉํ•˜์—ฌ ์‘๋‹ตํ•จ ๐Ÿ‘‰ ์—ฐ๊ฒฐ ์œ„์กฐ ๋ฐฉ์ง€์šฉ ๋ณด์•ˆ ์ ˆ์ฐจ

๐Ÿ“Œ โท Data Transfer

WebSocket์€ ์–‘๋ฐฉํ–ฅ(bidirectional) ํ†ต์‹ ์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ,
๋ฐ์ดํ„ฐ๋Š” ๋ฉ”์‹œ์ง€ ๋‹จ์œ„๋กœ, ๊ทธ ๋ฉ”์‹œ์ง€๋Š” ํ”„๋ ˆ์ž„(Frame) ๋‹จ์œ„๋กœ ๋ถ„ํ•  ์ „์†ก๋œ๋‹ค

๐Ÿ” Bidirectional WebSocket Message

  • ์„œ๋ฒ„ โ†” ํด๋ผ์ด์–ธํŠธ ๋ชจ๋‘ ๋ฉ”์‹œ์ง€๋ฅผ ์ž์œ ๋กญ๊ฒŒ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Œ
  • ๋ฉ”์‹œ์ง€๋ฅผ ํ”„๋ ˆ์ž„์œผ๋กœ ๋‚˜๋ˆ  ๋ณด๋‚ด๋Š” ๊ตฌ์กฐ

โœ”๏ธ Websocket Frame ๊ตฌ์กฐ

[WebSocket ๋ฉ”์‹œ์ง€]
 โ””โ”€โ”€ ํ•˜๋‚˜ ์ด์ƒ์˜ ํ”„๋ ˆ์ž„์œผ๋กœ ๊ตฌ์„ฑ๋จ
       โ””โ”€โ”€ ๊ฐ ํ”„๋ ˆ์ž„์€ ๋‹ค์Œ์„ ํฌํ•จ:
           - FIN (๋ฉ”์‹œ์ง€์˜ ๋์ธ์ง€)
           - Opcode (ํ…์ŠคํŠธ์ธ์ง€, ๋ฐ”์ด๋„ˆ๋ฆฌ์ธ์ง€ ๋“ฑ)
           - Masking key (๋ณด์•ˆ์šฉ)
           - Payload (์‹ค์ œ ๋ฐ์ดํ„ฐ)

ํƒ€์ž…, ๊ธธ์ด, ์‹ค์ œ ๋ฐ์ดํ„ฐ(payload) ๋“ฑ์„ ํฌํ•จํ•œ๋‹ค !
.... ๋งŒ์•ฝ ์กฐ๊ธˆ ๋” ์ž์„ธํžˆ ์›น์†Œ์ผ“์˜ ํ”„๋ ˆ์ž„์„ ์‚ดํŽด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค
( ์—ฌ๊ธฐ์„œ๋ถ€ํ„ด ์ง„์งœ ์•ˆ๋ด๋„ ๋œ๋‹ค ๋‚˜๋Š” ๊ทธ๋ƒฅ ์‹ค์ œ ํ”„๋ ˆ์ž„ ๋ชจ์Šต์ด ๊ถ๊ธˆํ–ˆ๋‹ค )

๐Ÿ’ก Websocket Frame

 0               1               2               3
 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
|I|S|S|S| (4)   |A|     (7)     |             (16/64)           |
|N|V|V|V|       |S|             |   (if payload len==126/127)   |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
 4               5               6               7
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|     Extended payload length continued, if payload len == 127  |
+ - - - - - - - - - - - - - - - +-------------------------------+
 8               9               10              11
+ - - - - - - - - - - - - - - - +-------------------------------+
|                               |Masking-key, if MASK set to 1  |
+-------------------------------+-------------------------------+
 12              13              14              15
+-------------------------------+-------------------------------+
| Masking-key (continued)       |          Payload Data         |
+-------------------------------- - - - - - - - - - - - - - - - +
:                     Payload Data continued ...                :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|                     Payload Data continued ...                |
+---------------------------------------------------------------+
  • FIN : ๋งˆ์ง€๋ง‰ ๋ฉ”์„ธ์ง€์ž„์„ ๋‚˜ํƒ€๋ƒ„ / FIN = 0์ด๋ฉด ๋‹ค์Œ ๋ฉ”์„ธ์ง€ ์žˆ์Œ, FIN = 1์ด๋ฉด ์ „์ฒด๋ฉ”์„ธ์ง€ ๋„์ฐฉ์™„๋ฃŒ
  • opcode : payload์˜ ๋ฐ์ดํ„ฐ ํฌ๋งท์„ ๋‚˜ํƒ€๋ƒ„
    • 0x0์€ continuation, 0x1์€ ํ…์ŠคํŠธ(UTF-8), 0x2 ๋ฐ”์ด๋„ˆ๋ฆฌ ๋ฐ์ดํ„ฐ...
  • MASK : ๋ฉ”์„ธ์ง€์˜ ๋งˆ์Šคํ‚น ์—ฌ๋ถ€ / ํด๋ผ์ด์–ธํŠธ - ์„œ๋ฒ„๋กœ ๊ฐ€๋Š” ๋ฉ”์„ธ์ง€๋Š” ํ•ญ์ƒ ๋งˆ์Šคํ‚น๋˜์–ด์•ผ..
  • payload : ๋ณด๋‚ด๊ณ ์ž ํ•˜๋Š” ์‹ค์ œ ๋ฐ์ดํ„ฐ
  • payload length : ํŽ˜์ด๋กœ๋“œ์˜ ๊ธธ์ด

๐Ÿ” opcode 0x0 ?
ํ•˜๋‚˜์˜ ๋ฉ”์„ธ์ง€๋ฅผ ์—ฌ๋Ÿฌ ํ”„๋ ˆ์ž„์œผ๋กœ ๋‚˜๋ˆ  ์ „์†กํ•  ๋•Œ ์‚ฌ์šฉ!
์ด๊ฑฐ n๊ฐœ์˜ ๋ฉ”์„ธ์ง€ ์ค‘ ์ค‘๊ฐ„์ด์•ผ! ๋’ค์— ๋” ์žˆ์Œ ๊ทผ๋ฐ ํ•œ ๋ฉ”์„ธ์ง€์ž„~์„ ํ‘œ์‹œ


โœ”๏ธ ping pong์œผ๋กœ ์—ฐ๊ฒฐ ์ƒํƒœ ํ™•์ธ

  • ping : Websocket ์—ฐ๊ฒฐ ์ค‘์ด๋ผ๋ฉด ํด๋ผ์ด์–ธํŠธ๋Š” ping์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Œ opcode = 0x9
  • pong : ์„œ๋ฒ„๋Š” ping์„ ๋ฐ›์œผ๋ฉด payload๋ฅผ ๊ทธ๋Œ€๋กœ ๋‹ด์•„ pong์„ ๋ณด๋ƒ„ opcode = 0xA
    ๐ŸŒŸ ping pong์„ ํ™œ์šฉํ•ด ์›น์†Œ์ผ“ ์—ฐ๊ฒฐ์˜ Open-Close ์—ฌ๋ถ€๋ฅผ ์ฃผ๊ธฐ์ ์œผ๋กœ ํ™•์ธ ๊ฐ€๋Šฅ

โž• ์‹ค์ œ ์ฝ”๋“œ ์˜ˆ์‹œ๋กœ ์ดํ•ดํ•˜๊ธฐ

  • Websocket์€ ์–‘๋ฐฉํ–ฅ ๋ฉ”์„ธ์ง€๋ฅผ send() ๋ฉ”์„œ๋“œ๋กœ ๋ณด๋‚ด๊ณ ,
  • onmessage๋‚˜ handleTextMessage() ๊ฐ™์€ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์—์„œ ์ˆ˜์‹  ๋ฉ”์„ธ์ง€๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค

ํด๋ผ์ด์–ธํŠธ โ†’ ์„œ๋ฒ„๋กœ ๋ฉ”์‹œ์ง€ ๋ณด๋‚ด๊ธฐ

const socket = new WebSocket("ws://localhost:8080/ws-endpoint");
socket.send("Hello, Server"); // ๋ฉ”์‹œ์ง€ ์ „์†ก
socket.onmessage = (event) => {
  console.log("Message from Server:", event.data); // ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์œผ๋ฉด ์‹คํ–‰๋˜๋Š” ๋ฆฌ์Šค๋„ˆ
};

์„œ๋ฒ„ โ†’ ํด๋ผ์ด์–ธํŠธ๋กœ ์‘๋‹ต ์ฒ˜๋ฆฌ (Spring WebSocket)

@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
    String payload = message.getPayload(); // ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ธ ๋ฉ”์‹œ์ง€ ์ถ”์ถœ
    session.sendMessage(new TextMessage("Received: " + payload)); // ์‘๋‹ต ๋ณด๋‚ด๊ธฐ
}

โ— ๋‹ค์ˆ˜์˜ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ธŒ๋กœ๋“œ์บ์ŠคํŠธํ•˜๋ ค๋ฉด?

for (WebSocketSession sess : sessions) {
    sess.sendMessage(new TextMessage("Broadcast: " + payload));
}

๐Ÿ“Œ โธ Close

  • Websocket ์—ฐ๊ฒฐ ์ข…๋ฃŒ๋ฅผ ์˜๋ฏธํ•œ๋‹ค opcode = 0x8
  • ํด๋ผ์ด์–ธํŠธ, ์„œ๋ฒ„ ์–ด๋А ์ชฝ์ด๋“  ์ข…๋ฃŒ๋ฅผ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Websocket์—๋„ ์ƒํƒœ์ฝ”๋“œ๊ฐ€ ์กด์žฌํ•˜์ง€๋งŒ, ์—ฐ๊ฒฐ ์ข…๋ฃŒ์‹œ (Close Frame)์—์„œ๋งŒ ์“ฐ์ธ๋‹ค!
    ( ์ตœ์ดˆ Handshake์‹œ ์„ฑ๊ณต ์‘๋‹ต์ธ 101์€ Http status code์ž„ )

๐Ÿ“ŽWebsocket Close Status Code
1000 : ์ •์ƒ ์ข…๋ฃŒ
1001 : ์—ฐ๊ฒฐ ์ฃผ์ฒด ์ค‘ ํ•œ์ชฝ ์†Œ์‹ค
1009 : ๋ฉ”์„ธ์ง€๊ฐ€ ์ปค์„œ ์ฒ˜๋ฆฌ ์‹คํŒจ
1011 : ์„œ๋ฒ„์˜ ๋น„์ •์ƒ ์—๋Ÿฌ ๋ฐœ์ƒ


๐Ÿšซ Websocket์˜ ํ•œ๊ณ„์ 

1. ๋ฐ์ดํ„ฐ ํ•ด์„์˜ ์–ด๋ ค์›€

  • payload์— ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด์•„ ์ „์†กํ•˜์ง€๋งŒ, ์ผ์ •ํ•œ ํ˜•์‹(json, xml ๋“ฑ,,,)์ด ์ •ํ•ด์ ธ ์žˆ์ง€์•Š๋‹ค
  • ๋”ฐ๋ผ์„œ ์„œ๋ฒ„๋‚˜ ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” ๋ฌธ์ž์—ด์„ ํ•ด์„ํ•˜๋Š” ์ž‘์—…(ํŒŒ์‹ฑ)์ด ํ•„์š”ํ•œ๋ฐ

๐Ÿ“Œ ํ•ด๊ฒฐ์ฑ… : ์„œ๋ธŒ ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•œ๋‹ค (๋Œ€ํ‘œ์ ์ธ ํ•˜์œ„ ํ”„๋กœํ† ์ฝœ : stomp)

2. ์—ฐ๊ฒฐ ์œ ์‹ค ๋ฐ ํ˜ธํ™˜์„ฑ ์ด์Šˆ

  • ์ผ๋ถ€ ๋ธŒ๋ผ์šฐ์ €๋Š” WebSocket์˜ Upgrade ํ—ค๋”๋ฅผ ์ธ์‹ํ•˜์ง€ ๋ชปํ•˜๊ฑฐ๋‚˜
  • ์˜ค๋žœ ์œ ํœด์ƒํƒœ์ผ TCP ์—ฐ๊ฒฐ์„ ์กฐ๊ธฐ ์ข…๋ฃŒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Œ
    โž HTTP์™€ ๋‹ฌ๋ฆฌ WebSocket์€ ๊ธฐ์กด ์ธํ”„๋ผ์™€ ์™„์ „ํžˆ ํ˜ธํ™˜๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค

๐Ÿ“Œ ํ•ด๊ฒฐ์ฑ… : SockJS(์Šคํ”„๋ง>stomp) , Socket.io(๋…ธ๋“œ)๋กœ ์›น์†Œ์ผ“ ๋ฏธ์ง€์›ํ™˜๊ฒฝ์—์„œ ์šฐํšŒ ์—ฐ๊ฒฐ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Œ



๐Ÿ™‹๐Ÿปโ€โ™€๏ธ์ด๋ ‡๊ฒŒ ์‹ค์‹œ๊ฐ„ ํ†ต์‹ ์„ ์œ„ํ•œ ๋ช‡๊ฐ€์ง€ ๊ธฐ์ˆ ๋“ค์„ ์‚ดํŽด๋ดค๋‹ค
SSE๋Š” ์‹ค์‹œ๊ฐ„ ํ†ต์‹ ์ด ํ•„์š”ํ•œ ์„œ๋น„์Šค์—์„œ Polling์„ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ„๋‹จํ•˜๊ณ  ๊ฐ•๋ ฅํ•œ ์˜ต์…˜์ด์ง€๋งŒ,
์–‘๋ฐฉํ–ฅ ํ†ต์‹ ์ด๋‚˜ ๊ณ ๊ธ‰ ๋ฉ”์‹œ์ง• ๊ตฌ์กฐ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด WebSocket ๊ธฐ๋ฐ˜์œผ๋กœ ๋„˜์–ด๊ฐ€๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ด๋‹ค.
๋”ฐ๋ผ์„œ ๋‚˜๋Š” Websocket + ์„œ๋ธŒ ํ”„๋กœํ† ์ฝœ์ธ STOMP๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค

1๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2025๋…„ 6์›” 26์ผ

๋•๋ถ„์— ์ €๋„ ์ ์šฉํ•ด๋ณผ ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์•„์š”!

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ