๐๐ปโโ๏ธ์ผ๊ตฌ ์ค์๊ฐ ์ํต ํ๋ซํผ์ ๋ผ์ด๋ธ ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ ์ค,
websocket + stomp๋ฅผ ์ฌ์ฉํด ์ค์๊ฐ ์ฑํ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ค.
์ค์๊ฐ ํต์ ์ ์ํ
1. websocket ๋ฑ์ฅ ์ด์ ์ ๋ฐฉ์2. ๋จ๋ฐฉํฅ ํต์ (SSE)3. ์๋ฐฉํฅ ํต์ (Websocket)์ ๋ํด ์ ๋ฆฌํ๋ค
๊ธฐ์กด์ Http ํต์ ์
ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์๊ฒ ์์ฒญ์ ๋ณด๋ด๊ณ , ์๋ต์ ๋ฐ๋ HTTP ๊ธฐ๋ฐ ๋จ๋ฐฉํฅ ํต์ ์ด๋ค
๐ซํ๊ณ : HTTP ํต์ ์ Stateless, Connectionlessํ ํน์ฑ
์๋ฅผ ๋ค์ด, ๋ด๊ฐ ์ง๊ธ ๊ตฌํํ๊ณ ์ ํ๋ ์ค์๊ฐ ์ฑํ
์ ๊ฒฝ์ฐ,
์ฑํ
๋ฐฉ์ ์ฐธ์ฌ์ค์ธ ๋ชจ๋ ์๋๋ฐฉ์ ๋ฉ์ธ์ง๋ฅผ ๋ฐ๊ธฐ์ํด์๋ ๋งค๋ฒ ์์ฒญ์ ๋ณด๋ด์ผํจ
๋ด๊ฐ ๋จผ์ ๋ฉ์ธ์ง๋ฅผ ๋ณด๋ผ ์ ์์ง๋ง, ์๋ฒ๋ ์ ํก์ ํ์ง ์๋๋ค..^^
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ Http ์์์ ๊ธฐ์ ์ ์๋์ ๊ฐ๋ค
ํด๋ผ์ด์ธํธ๊ฐ ์ผ์ ์ฃผ๊ธฐ๋ก http request๋ฅผ ๋ณด๋ธ๋ค
๐ซ ๋จ์
ํด๋ผ์ด์ธํธ์ request๋ฅผ ์๋ฒ๋ ์ผ์ ์๊ฐ ๋๊ธฐ ํ ์๋ต์ ์ค๋ค
์๋ต๊น์ง์ ์๊ฐ์ ์ต๋ํ ๋๋ ค์ ์ด๋ฒคํธ ๋ฐ์์๊น์ง ๋๊ธฐํ๋ค
1. ํด๋ผ์ด์ธํธ์์ ์๋ฒ๋ก http request๋ฅผ ๋ณด๋ด๋ฉด
2. ์๋ฒ๋ ์ฐ๊ฒฐ์ ์๋๊ณ ๊ธฐ๋ค๋ฆผ
3. ์ด๋ฒคํธ ๋ฐ์์ ์๋ฒ๋ ์๋ต์ ์ฃผ๊ณ ์ฐ๊ฒฐ ์ข
๋ฃ
4. ํด๋ผ์ด์ธํธ๋ 3๋ฒ์์ ์๋ต์ ๋ฐ๊ณ ๋ค์ ์์ฒญ์ ๋ณด๋ธ๋ค
๐ซ ๋จ์
์๋ฒ์์ ํด๋ผ์ด์ธํธ์๊ฒ ์ค์๊ฐ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๋ ๊ธฐ์ ์ด๋ค
๊ธฐ๋ณธ์ ์ผ๋ก 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: ์ด๋ฒคํธ ์ ๋ฌ
๐ ๋ฐ์ดํฐ ํ์ -
name:valueevent: type1 data: An event of type1. event: type2 data: An event of type2.
โญ๏ธ ์ฅ์
EventSource๊ฐ ์๋์ผ๋ก ์ฌ์ฐ๊ฒฐ์ ์๋ํจโ ๋จ์
payload์ ํฌ๊ธฐ๊ฐ ์ ํ์ ์ด๋คWebSocket์ ๊ธฐ๋ณธ HTTP ํธ๋์ ฐ์ดํฌ๋ฅผ ํตํด ์ฐ๊ฒฐ์ ์์ํ๊ณ ,
์ดํ์๋ ์ง์์ ์ธ TCP ์ฐ๊ฒฐ์ ํตํด ์๋ฐฉํฅ ํต์ ์ด ๊ฐ๋ฅํ ํ๋กํ ์ฝ์ด๋ค๐ TCP = ์ฐ๊ฒฐ์งํฅ ํ๋กํ ์ฝ (http์ connectionless์ ๋๋น๋จ)
Websocket์ ๋์์ 1๏ธโฃ handshake , 2๏ธโฃ Data transfer, 3๏ธโฃ Close Handshake ์ ๊ณผ์ ์ ๊ฑฐ์น๋ค
๊ณผ์ ๋ณ๋ก ์์ธํ ์ดํด๋ณด์ !
GETโ๏ธ 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 ์ธ์ฝ๋ฉํ์ฌ ์๋ตํจ ๐ ์ฐ๊ฒฐ ์์กฐ ๋ฐฉ์ง์ฉ ๋ณด์ ์ ์ฐจ
WebSocket์ ์๋ฐฉํฅ(bidirectional) ํต์ ์ด ๊ฐ๋ฅํ๋ฉฐ,
๋ฐ์ดํฐ๋ ๋ฉ์์ง ๋จ์๋ก, ๊ทธ ๋ฉ์์ง๋ ํ๋ ์(Frame) ๋จ์๋ก ๋ถํ ์ ์ก๋๋ค
๐ Bidirectional WebSocket Message
[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๊ฐ์ ๋ฉ์ธ์ง ์ค ์ค๊ฐ์ด์ผ! ๋ค์ ๋ ์์ ๊ทผ๋ฐ ํ ๋ฉ์ธ์ง์~์ ํ์
opcode = 0x9opcode = 0xAํด๋ผ์ด์ธํธ โ ์๋ฒ๋ก ๋ฉ์์ง ๋ณด๋ด๊ธฐ
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)); }
opcode = 0x8๐Websocket Close Status Code
1000 : ์ ์ ์ข ๋ฃ
1001 : ์ฐ๊ฒฐ ์ฃผ์ฒด ์ค ํ์ชฝ ์์ค
1009 : ๋ฉ์ธ์ง๊ฐ ์ปค์ ์ฒ๋ฆฌ ์คํจ
1011 : ์๋ฒ์ ๋น์ ์ ์๋ฌ ๋ฐ์
ํ์ฑ)์ด ํ์ํ๋ฐ๐ ํด๊ฒฐ์ฑ : ์๋ธ ํ๋กํ ์ฝ์ ์ฌ์ฉํ๋ค (๋ํ์ ์ธ ํ์ ํ๋กํ ์ฝ : stomp)
๐ ํด๊ฒฐ์ฑ : SockJS(์คํ๋ง>stomp) , Socket.io(๋ ธ๋)๋ก ์น์์ผ ๋ฏธ์ง์ํ๊ฒฝ์์ ์ฐํ ์ฐ๊ฒฐ ์๋ํ ์ ์์
๐๐ปโโ๏ธ์ด๋ ๊ฒ ์ค์๊ฐ ํต์ ์ ์ํ ๋ช๊ฐ์ง ๊ธฐ์ ๋ค์ ์ดํด๋ดค๋ค
SSE๋ ์ค์๊ฐ ํต์ ์ด ํ์ํ ์๋น์ค์์ Polling์ ๋์ฒดํ ์ ์๋ ๊ฐ๋จํ๊ณ ๊ฐ๋ ฅํ ์ต์ ์ด์ง๋ง,
์๋ฐฉํฅ ํต์ ์ด๋ ๊ณ ๊ธ ๋ฉ์์ง ๊ตฌ์กฐ๊ฐ ํ์ํ๋ค๋ฉด WebSocket ๊ธฐ๋ฐ์ผ๋ก ๋์ด๊ฐ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ด๋ค.
๋ฐ๋ผ์ ๋๋ Websocket + ์๋ธ ํ๋กํ ์ฝ์ธ STOMP๋ฅผ ์ฌ์ฉํ๋ค
๋๋ถ์ ์ ๋ ์ ์ฉํด๋ณผ ์ ์์ ๊ฒ ๊ฐ์์!