Skip to content

๐Ÿ“ฎ SSE(Server Sent Events)

PARK NA HYUN edited this page Nov 15, 2024 · 5 revisions

SSE๋ž€?

image.png

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


SSE ์‚ฌ์šฉ ์ด์œ 

๋ฐฉ ์ƒ์„ฑ ๋‹ค์ด์–ด๊ทธ๋žจ
sequenceDiagram
    participant Client
    participant GameSocket
    participant SignalingSocket
    participant Store
    participant REST
    participant SSE

    %% useRoomsSSE ํ›… ์‹คํ–‰
    Note over Client: useRoomsSSE ํ›… ๋งˆ์šดํŠธ

    %% getRoomsQuery๋กœ ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ๋กœ๋“œ
    Client->>REST: react-query getRoomsQuery() ์‹คํ–‰
    REST-->>Client: initialRooms ๋ฐ์ดํ„ฐ
    Client->>Store: setRooms(initialRooms)

    %% SSE ์—ฐ๊ฒฐ ์„ค์ •
    Client->>SSE: new EventSource(ENV.SSE_URL)
    SSE-->>Client: onopen: ์—ฐ๊ฒฐ ์„ฑ๊ณต

    Note over Client,SSE: SSE ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ์„ค์ •

    loop SSE ์‹ค์‹œ๊ฐ„ ์—…๋ฐ์ดํŠธ
        SSE->>Client: onmessage: rooms ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ
        Note over Client: JSON.parse(event.data)
        Client->>Store: setRooms(rooms)
        Store-->>Client: UI ๋ฆฌ๋ Œ๋”๋ง
    end

    Note over Client,SSE: ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ
    SSE->>Client: onerror: ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋ฐ ์—ฐ๊ฒฐ ์ข…๋ฃŒ

    %% ๋ฐฉ ์ƒ์„ฑ ํ๋ฆ„
    Note over Client: ๋ฐฉ ๋งŒ๋“ค๊ธฐ ๋ฒ„ํŠผ ํด๋ฆญ
    Client->>Client: CreateDialog ์˜คํ”ˆ
    Note over Client: ๋ฐฉ ์ œ๋ชฉ/๋‹‰๋„ค์ž„ ์ž…๋ ฅ

    par Socket Connections
        Client->>GameSocket: gameSocket.connect()
        GameSocket-->>Client: ์—ฐ๊ฒฐ ์„ฑ๊ณต
        Client->>SignalingSocket: signaligSocket.connect()
        SignalingSocket-->>Client: ์—ฐ๊ฒฐ ์„ฑ๊ณต
    end

    Client->>GameSocket: emit('createRoom', {roomName, hostNickname})
    GameSocket-->>Store: roomCreated ์ด๋ฒคํŠธ (room ๋ฐ์ดํ„ฐ)
    Store-->>Client: ์ƒํƒœ ์—…๋ฐ์ดํŠธ

    Client->>SignalingSocket: emit('joinRoom', room)
    SignalingSocket-->>Client: WebRTC ์—ฐ๊ฒฐ ์„ค์ •


    Client->>SSE: eventSource.close()
Loading

create-and-join-room

  1. ๋ฐฉ ๋งŒ๋“ค๊ธฐ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, ๋ฐฉ ์ œ๋ชฉ๊ณผ ๋‹‰๋„ค์ž„์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ ์ƒ์„ฑ Dialog๊ฐ€ ์˜คํ”ˆ๋˜๊ณ , ๋ฐฉ ์ œ๋ชฉ๊ณผ ๋‹‰๋„ค์ž„์„ ์ž…๋ ฅ ํ›„ ํ™•์ธ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด Game Server Socket๊ณผ Signaling Server Socket์— ์—ฐ๊ฒฐํ•˜๊ณ , gameSocket์˜ createRoom ์ด๋ฒคํŠธ๋ฅผ emit ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœ, signaligSocket์˜ joinRoom ์ด๋ฒคํŠธ๋ฅผ emit ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
  2. ํด๋ผ์ด์–ธํŠธ ์ธก ๋ Œ๋”๋ง์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋Š” gameSocket์„ ํ†ตํ•ด์„œ ๋ฐ›์•„์™€ Store์— ์ €์žฅ ํ›„ ๋ Œ๋”๋ง์„ ํ•ด์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, createRoom์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ๊ฒŒ์ž„๋ฐฉ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์™€์„œ ๋ฐฉ ๋ชฉ๋ก ๋ฐฐ์—ด์— ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ฐฉ ๋ชฉ๋ก ํŽ˜์ด์ง€์—์„œ ๋ Œ๋”๋ง์„ ํ•ด์ค๋‹ˆ๋‹ค.
  3. ์—ฌ๊ธฐ์„œ ๋ฌธ์ œ๋Š” โ€œ๋ฐฉ ์ƒ์„ฑโ€์ด๋ผ๋Š” ์ด๋ฒคํŠธ๋ฅผ ํ†ตํ•ด ์†Œ์ผ“์ด ์—ฐ๊ฒฐ๋˜๊ณ  ์žˆ์–ด, ๋ฐฉ ๋ชฉ๋ก ํŽ˜์ด์ง€์— ์ฒ˜์Œ ์ง„์ž…ํ•œ ์‚ฌ์šฉ์ž์˜ ๊ฒฝ์šฐ ์ €์žฅ๋œ ์ƒํƒœ๊ฐ€ ์—†๊ณ , ๋ฐฉ ๋ชฉ๋ก ํŽ˜์ด์ง€์—์„œ ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•œ ์‚ฌ์šฉ์ž์˜ ๊ฒฝ์šฐ ์ƒํƒœ๊ฐ€ ์ดˆ๊ธฐํ™”๋˜์–ด ๋ฐฉ ๋ชฉ๋ก์ด ๋ณด์ด์ง€ ์•Š๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  4. ์šฐ์„  ์ด ๋ถ€๋ถ„์„ polling ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. polling ๋ฐฉ์‹์ด๋ž€, ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„ ์ธก์— ์ฃผ๊ธฐ์ ์œผ๋กœ API ์š”์ฒญ์„ ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. react-query๋ฅผ ์ฒ˜์Œ ์‚ฌ์šฉํ•ด ๋ด์„œ refetchInterval ์˜ต์…˜์ด ์žˆ๋Š” ์ค„ ๋ชฐ๋ž์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ setInterval๋กœ ์ฃผ๊ธฐ๋ฅผ ์„ค์ •ํ•ด refetchํ•˜์—ฌ ๋ฆฌ๋ Œ๋”๋งํ•ด ์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.
  5. ์ด ๋ฐฉ์‹์˜ ๋ฌธ์ œ์ ์€ ์ƒˆ๋กœ์šด ๋ฐฉ์ด ์ƒ์„ฑ๋˜์ง€ ์•Š๋”๋ผ๋„, ์ฆ‰ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์—†๋Š” ๊ฒฝ์šฐ์—๋„ ๋ถˆํ•„์š”ํ•œ API ์š”์ฒญ์ด ๊ณ„์† ๋ฐœ์ƒํ•˜์—ฌ ์„œ๋ฒ„์— ๋ถ€ํ•˜๋ฅผ ์ค„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ, ์—„๊ฒฉํ•˜๊ฒŒ Interval ์‹œ๊ฐ„๋งŒํผ ์ง€์—ฐ์ด ๋ฐœ์ƒํ•˜์—ฌ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ˜์˜๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์—๋„ ์ข‹์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•˜์—ฌ SSE๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ์Šต๋‹ˆ๋‹ค.

SSE๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด REST API๋Š” ํ•„์š”์—†์„๊นŒ?๐Ÿค”

์ €ํฌ ํŒ€์—์„œ๋Š” ์ฒ˜์Œ์— SSE๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด REST API ์š”์ฒญ์€ ์“ธ ์ผ์ด ์—†์„ ๊ฒƒ ๊ฐ™๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ SSE๋กœ๋งŒ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋˜์—ˆ๋Š”๋ฐ, ํด๋ผ์ด์–ธํŠธ ์ชฝ์—์„œ SSE ์—ฐ๋™ ํ›„ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด ๋ณด๋Š” ๊ณผ์ •์—์„œ ์ž˜๋ชป๋œ ์ƒ๊ฐ์ด์—ˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

SSE๋„ ์„œ๋ฒ„์— ๋ฐœ์ƒํ•˜๋Š” ์ƒˆ๋กœ์šด ์ด๋ฒคํŠธ(๋ณ€๊ฒฝ ์‚ฌํ•ญ)๋ฅผ ๋ฐ›์•„ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•ด ์ฃผ๋Š” ๋ฐฉ์‹์ด๊ธฐ ๋•Œ๋ฌธ์—, ํŽ˜์ด์ง€๋ฅผ ์ฒ˜์Œ ๋กœ๋“œํ•˜๊ฑฐ๋‚˜ ์ƒˆ๋กœ๊ณ ์นจ ํ•  ๋•Œ์˜ ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ์˜ ๊ฒฝ์šฐ REST API๋ฅผ ์‚ฌ์šฉํ•ด ๋ฐ›์•„์™€์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„ ์˜จ ์ดํ›„์— ๋ฐœ์ƒํ•˜๋Š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์€ SSE๋ฅผ ์‚ฌ์šฉํ•ด ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ˜์˜ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.


SSE vs WebSocket

ํŠน์„ฑ SSE WebSocket
์—ฐ๊ฒฐ ๋ฐฉ์‹ HTTP ๊ธฐ๋ฐ˜ ๋…๋ฆฝ์ ์ธ ์—ฐ๊ฒฐ (TCP)
์ „์†ก ๋ฐฉํ–ฅ ์„œ๋ฒ„ โ†’ ํด๋ผ์ด์–ธํŠธ (๋‹จ๋ฐฉํ–ฅ) ์„œ๋ฒ„ โ†” ํด๋ผ์ด์–ธํŠธ (์–‘๋ฐฉํ–ฅ)
๋ธŒ๋ผ์šฐ์ € ์ง€์› ๋Œ€๋ถ€๋ถ„ ์ง€์› ์ผ๋ถ€ ๋ธŒ๋ผ์šฐ์ €์—์„œ๋งŒ ์ง€์›
๋ณด์•ˆ์„ฑ HTTPS ์‚ฌ์šฉ ๊ฐ€๋Šฅ HTTPS ์‚ฌ์šฉ ๊ฐ€๋Šฅ

SSE Client ์‚ฌ์šฉ ์˜ˆ์‹œ

// ์„œ๋ฒ„ URL์„ ์‹ค์ œ URL๋กœ ๋ณ€๊ฒฝํ•˜์„ธ์š” (์˜ˆ: http://localhost:8000)
const serverUrl = 'http://localhost:8000/api/rooms';

const eventSource = new EventSource(serverUrl);

eventSource.onmessage = function (event) {
  console.log('New message:', event.data);
};

eventSource.onerror = function (error) {
  console.error('EventSource failed:', error);
};

์•ˆ๋…•! ํด๋กœ๋ฐ”ํŒŒํŠธ๋ผ

ํŒ€ ๋ฌธํ™”

๐Ÿค Ground Rule

ํ˜‘์—… ๋ฐฉ์‹

๐Ÿ”’ Convention
๐ŸŒณ Git Branch ์ „๋žต

๊ฐœ๋ฐœ ๋ฌธ์„œ

๐Ÿ› ๏ธ AGT - Automatic Git & Github Tool
๐Ÿ“Š WebRTC Mesh โ€ ํŠธ๋ž˜ํ”ฝ ๊ณ„์‚ฐ
๐ŸŽข WebRTC Mesh - ํ—˜๋‚œํ•œ ์—ฌ์ •
๐Ÿ’ฌ WebRTC๋ฅผ ์•Œ์•„๋ณด์ž
๐Ÿ“ฎ SSE(Server Sent Events)
๐Ÿ“– SSE Pagination
โณ Socket ํ†ต์‹ ์—์„œ ๋น„๋™๊ธฐ ์ž‘์—… ์ˆœ์„œ ๋ณด์žฅ ๋ฐฉ๋ฒ•
๐Ÿ“ก Redis pub/sub๋ฅผ ํ™œ์šฉํ•œ SSE ์ ์šฉ๊ธฐ
๐Ÿ—๏ธ Naver Cloud Platform์„ ํ™œ์šฉํ•œ ๋ฐฐํฌ ์ „๋žต
โš”๏ธ๐Ÿš€ ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ: ๋‹จ์ผ ์ธ์Šคํ„ด์Šค VS NKS
๐Ÿšดโ€โ™€๏ธ Redis๋กœ ๊ฒŒ์ž„๋ฐฉ ๊ด€๋ฆฌ ์ตœ์ ํ™”: ํšจ์œจ์ ์ธ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ์™€ ์„ฑ๋Šฅ ๊ฐœ์„ 

ํšŒ์˜๋ก

๐Ÿ“† ํšŒ์˜๋ก ์บ˜๋ฆฐ๋”
๐Ÿ–ค ๋ฐ์ผ๋ฆฌ ์Šคํฌ๋Ÿผ ํ…œํ”Œ๋ฆฟ
๐Ÿ–ค ํšŒ๊ณ  ํ…œํ”Œ๋ฆฟ

๋ฉ˜ํ† ๋ง

0๏ธโƒฃ 0์ฃผ์ฐจ ๋ฉ˜ํ† ๋ง ์ผ์ง€
1๏ธโƒฃ 1์ฃผ์ฐจ ๋ฉ˜ํ† ๋ง ์ผ์ง€
2๏ธโƒฃ 2์ฃผ์ฐจ ๋ฉ˜ํ† ๋ง ์ผ์ง€
3๏ธโƒฃ 3์ฃผ์ฐจ ๋ฉ˜ํ† ๋ง ์ผ์ง€
4๏ธโƒฃ 4์ฃผ์ฐจ ๋ฉ˜ํ† ๋ง ์ผ์ง€

๋ฐœํ‘œ

0๏ธโƒฃ 0์ฃผ์ฐจ ๋ฐœํ‘œ
1๏ธโƒฃ 1์ฃผ์ฐจ ๋ฐœํ‘œ
2๏ธโƒฃ 2์ฃผ์ฐจ ๋ฐœํ‘œ
3๏ธโƒฃ 3์ฃผ์ฐจ ๋ฐœํ‘œ
4๏ธโƒฃ 4์ฃผ์ฐจ ๋ฐœํ‘œ
5๏ธโƒฃ ์ตœ์ข… ๋ฐœํ‘œ

Clone this wiki locally