์›น์†Œ์ผ“ ํ”„๋กœ๊ทธ๋ž˜๋ฐ

1. HTTP ๋ฐ TCP/IP

1.1 TCP์™€ IP์˜ ์—ญํ• 

  • IP (Internet Protocol): ๋ฐ์ดํ„ฐ๋ฅผ ๋ชฉ์ ์ง€๊นŒ์ง€ ์ „๋‹ฌํ•˜๋Š” ์—ญํ• .

  • TCP๋Š” IP ์œ„์—์„œ ์ž‘๋™ํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ๋ฅผ ํŒจํ‚ท์œผ๋กœ ๋‚˜๋ˆ„์–ด ์ „์†กํ•œ ํ›„ ์ˆ˜์‹  ์ธก์—์„œ ์ด๋ฅผ ์žฌ์กฐ๋ฆฝ.

  • TCP (Transmission Control Protocol): ๋ฐ์ดํ„ฐ ์ „์†ก์˜ ์‹ ๋ขฐ์„ฑ์„ ๋ณด์žฅ.

1.2 HTTP ํ†ต์‹ ์˜ ํŠน์ง•

  • HTTP (Hypertext Transfer Protocol): ์š”์ฒญ-์‘๋‹ต ๊ธฐ๋ฐ˜์˜ ๋‹จ๋ฐฉํ–ฅ ํ†ต์‹  ํ”„๋กœํ† ์ฝœ.

  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด ์„œ๋ฒ„๊ฐ€ ์‘๋‹ตํ•˜๋Š” ๊ตฌ์กฐ๋กœ, ์ •์  ์ฝ˜ํ…์ธ  ๋กœ๋“œ, ํผ ๋ฐ์ดํ„ฐ ์ „์†ก, API ํ˜ธ์ถœ ๋“ฑ ์ผํšŒ์„ฑ ์š”์ฒญ์— ์ ํ•ฉ.

  • ์š”์ฒญ-์‘๋‹ต ๊ตฌ์กฐ: ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์„œ๋ฒ„๊ฐ€ ์‘๋‹ตํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ, ์š”์ฒญ๋งˆ๋‹ค ์ƒˆ ์—ฐ๊ฒฐ์„ ์„ค์ •ํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›์Œ.

  • ๋ฌด์ƒํƒœ์„ฑ: HTTP๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ฐ ์š”์ฒญ์ด ๋…๋ฆฝ์ . ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋ ค๋ฉด ์„ธ์…˜์ด๋‚˜ ์ฟ ํ‚ค์™€ ๊ฐ™์€ ์ถ”๊ฐ€ ์ž‘์—…์ด ํ•„์š”.


2. ์›น์†Œ์ผ“

2.1 ์›น์†Œ์ผ“์˜ ํŠน์ง•

  • ์‹ค์‹œ๊ฐ„ ํ†ต์‹ ์˜ ํ•„์š”์„ฑ์ด ์ปค์ง€๋ฉด์„œ 2011๋…„์— WebSocket์ด ํ‘œ์ค€ํ™”.

  • WebSocket์€ ์ด TCP๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž‘๋™ํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ๊ฐ€ ์ˆœ์„œ๋Œ€๋กœ ์ „์†ก๋˜๋„๋ก ํ•˜๊ณ  ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ ์ž๋™์œผ๋กœ ๋ณต๊ตฌ.

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

2.2 ์ ์ ˆํ•œ ์‚ฌ์šฉ ์˜ˆ์‹œ?

  • ์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ… ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜

  • ์‹ค์‹œ๊ฐ„ ๊ฒŒ์ž„

  • ์‹ค์‹œ๊ฐ„ ํ˜‘์—… ๋„๊ตฌ (์˜ˆ: ๊ณต๋™ ๋ฌธ์„œ ํŽธ์ง‘)

  • ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆฌ๋ฐ (์˜ˆ: ๋ผ์ด๋ธŒ ์Šคํฌ์ธ  ์ค‘๊ณ„)

2.3 ์žฅ๋‹จ์ 

  • ์žฅ์ 

    • ๋‚ฎ์€ ์ง€์—ฐ ์‹œ๊ฐ„, ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ๊ตํ™˜์— ์ตœ์ ํ™”๋จ

    • ํšจ์œจ์ ์ธ ๋ฐ์ดํ„ฐ ์ „์†ก, ํ—ค๋” ์˜ค๋ฒ„ํ—ค๋“œ ๊ฐ์†Œ

    • ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„๊ฐ€ ๋™์‹œ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ์Œ

  • ๋‹จ์ 

    • ์ง€์†์ ์ธ ์—ฐ๊ฒฐ๋กœ ์ธํ•œ ์„œ๋ฒ„ ์ž์› ์†Œ๋ชจ

    • ๊ตฌํ˜„ ๋ณต์žก์„ฑ ์ฆ๊ฐ€

    • ์ผ๋ถ€ ๋ฐฉํ™”๋ฒฝ์ด๋‚˜ ํ”„๋ก์‹œ์—์„œ ์ฐจ๋‹จ๋  ์ˆ˜ ์žˆ์Œ

2.4 ๋ธŒ๋ผ์šฐ์ € ์†Œ์ผ“ ์ดˆ๊ธฐํ™”

  const socket = new WebSocket('ws://192.168.55.28:8080');

2.5 ์„œ๋ฒ„๋กœ ๋ฐ์ดํ„ฐ ์ „์†กํ•˜๊ธฐ

      form.addEventListener('submit', function (e) {
        e.preventDefault();
        if (input.value) {
          const message = {
            clientId: clientId,
            message: input.value
          }
          socket.send(JSON.stringify(message));
          input.value = '';
        }
      });

2.6 ๋„คํŠธ์›Œํฌ ๋“ค์—ฌ๋‹ค๋ณด๊ธฐ

ํ•ธ๋“œ์‰์ดํฌ ๊ณผ์ •
  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„๋กœ ์š”์ฒญ ์ „์†ก

    • Sec-WebSocket-Key์™€ ํ•จ๊ป˜ WebSocket ์—ฐ๊ฒฐ ์š”์ฒญ์„ ๋ณด๋ƒ„.
  • ์„œ๋ฒ„๊ฐ€ Sec-WebSocket-Accept ์ƒ์„ฑ ํ›„ ์‘๋‹ต

    • ์„œ๋ฒ„๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ธ ํ‚ค๋ฅผ ์ด์šฉํ•ด Sec-WebSocket-Accept ํ—ค๋” ๊ฐ’์„ ์ƒ์„ฑํ•˜๊ณ  ์‘๋‹ต
  • ํด๋ผ์ด์–ธํŠธ์˜ ๊ฒ€์ฆ: ํด๋ผ์ด์–ธํŠธ๋Š” ์„œ๋ฒ„์˜ ์‘๋‹ต ๊ฐ’์„ ํ™•์ธํ•˜๊ณ  ์ผ์น˜ํ•˜๋ฉด WebSocket ์—ฐ๊ฒฐ์ด ์„ฑ๋ฆฝ

์ฐธ๊ณ . Request URL <socket.io ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ์‹œ>
  • EIO=4: Socket.IO ํ”„๋กœํ† ์ฝœ ๋ฒ„์ „( 4.x ํ”„๋กœํ† ์ฝœ ์‚ฌ์šฉ)

  • transport=websocket: ํ˜„์žฌ ์ „์†ก ๋ฐฉ์‹์„ ์ง€์ •.

  • sid=1kbDBngrZ9P44RmsAAAl: ์„ธ์…˜ ID๋กœ, ์„œ๋ฒ„์—์„œ ๊ฐ ํด๋ผ์ด์–ธํŠธ๋ฅผ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด ๋ถ€์—ฌํ•˜๋Š” ๊ณ ์œ  ID

2.7 ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ ์ˆ˜์‹ 

      socket.onmessage = function (event) {
        const item = document.createElement('li');

        event.data.text().then((text) => {
          let {clientId, message}= JSON.parse(text)

          if(clientId === myId) {
            item.classList.add('mine');
          } else {
            message = `${clientId}: ${message}`;
          }

          item.textContent = message;
          messages.appendChild(item);
          window.scrollTo(0, document.body.scrollHeight);
        });

      };

2.8 ์„œ๋ฒ„ ์ฝ”๋“œ ์˜ˆ์‹œ

const WebSocket = require('ws');
const express = require('express');
const app = express();
const server = require('http').createServer(app);

const wsServer = new WebSocket.Server({ server });

wsServer.on('connection', function connection(ws) {
  ws.on('message', function incoming(message) {
    // ๋ฐ›์€ ๋ฉ”์‹œ์ง€๋ฅผ ๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ „์†ก
    console.log('received: %s', message);
    wsServer.clients.forEach(function each(client) {
      if (client.readyState === WebSocket.OPEN) {
        client.send(message);
      }
    });
  });
});

app.use(express.static('public'));

const PORT = process.env.PORT || 8080;
server.listen(PORT, () => console.log(`Server is running on http://localhost:${PORT}`));

2.9 ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ (React)

import React, { useEffect, useRef } from 'react';

const Canvas = () => {
  const canvasRef = useRef(null);
  const socketRef = useRef(null);

  useEffect(() => {
    socketRef.current = new WebSocket('ws://localhost:8080');
    socketRef.current.onmessage = (event) => {
      const { x, y } = JSON.parse(event.data);
      draw(x, y);
    };
    return () => socketRef.current.close();
  }, []);

  const draw = (x, y) => {
    const canvas = canvasRef.current;
    const ctx = canvas.getContext('2d');
    ctx.fillStyle = 'black';
    ctx.fillRect(x, y, 2, 2);
  };

  const handleMouseMove = (event) => {
    const x = event.clientX;
    const y = event.clientY;
    draw(x, y);
    socketRef.current.send(JSON.stringify({ x, y }));
  };

  return <canvas ref={canvasRef} width={800} height={600} onMouseMove={handleMouseMove} />;
};

export default Canvas;

3. ๊ฐœ๋ฐœ ํŒ

3.1 ๋””๋ฒ„๊น…

  • ๋„คํŠธ์›Œํฌ ํƒญ ํ™œ์šฉ: ๋ธŒ๋ผ์šฐ์ € ๊ฐœ๋ฐœ์ž ๋„๊ตฌ์˜ ๋„คํŠธ์›Œํฌ ํƒญ์—์„œ WebSocket ์—ฐ๊ฒฐ ์ƒํƒœ์™€ ์ „์†ก๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ชจ๋‹ˆํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์Œ.

  • WebSocket ํ”„๋ ˆ์ž„(Frame) ํƒญ์—์„œ ์ฃผ๊ณ ๋ฐ›๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ํ™•์ธํ•˜์—ฌ ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ํŒŒ์•…

  • ์ฝ˜์†” ๋กœ๊ทธ: ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„์˜ ์†Œ์ผ“ ์—ฐ๊ฒฐ, ์†ก์ˆ˜์‹  ์ด๋ฒคํŠธ๋ฅผ ์ฝ˜์†”์— ์ถœ๋ ฅํ•ด ํ†ต์‹ ์ด ์ •์ƒ์ ์œผ๋กœ ์ด๋ฃจ์–ด์ง€๋Š”์ง€ ํ™•์ธ.

Vite___React

3.2 ์˜ค๋ฅ˜ - CORS

  • WebSocket ํ†ต์‹ ์—์„œ๋„ CORS ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ.

  • ํŠนํžˆ ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„๊ฐ€ ๋‹ค๋ฅธ ๋„๋ฉ”์ธ์— ์žˆ์„ ๊ฒฝ์šฐ ๋ธŒ๋ผ์šฐ์ €์—์„œ WebSocket ์—ฐ๊ฒฐ์„ ์ฐจ๋‹จํ•  ์ˆ˜ ์žˆ์Œ.

  • socket.io์—์„œ๋Š” ์„œ๋ฒ„์—์„œ CORS ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•˜์—ฌ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Œ.

const io = require('socket.io')(3000, {
cors: {
  origin: "http://localhost:3001",
  methods: ["GET", "POST"]
}
});

3.3 WebSocket ๋ณด์•ˆ์„ ์œ„ํ•œย wss://ย ์„ค์ •

๋ณด์•ˆ์ด ํ•„์š”ํ•œ WebSocket ํ†ต์‹ ์—์„œ๋Š”ย wss://ย ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•ด TLS ์•”ํ˜ธํ™”๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Œ.

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ์—์„œ TLS ์„ค์ •:ย wss://๋ฅผ ์ง€์›ํ•˜๋ ค๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ์—์„œ HTTPS ์„œ๋ฒ„๋ฅผ ์„ค์ •ํ•˜๊ณ  WebSocket ์„œ๋ฒ„๋ฅผ ๊ทธ ์œ„์— ๊ตฌ์„ฑ.
const https = require('https');
const WebSocket = require('ws');
const server = https.createServer({
  cert: fs.readFileSync('path/to/cert.pem'),
  key: fs.readFileSync('path/to/key.pem')
});
const wss = new WebSocket.Server({ server });
  • ํ”„๋ก์‹œ ์„œ๋ฒ„ ์ด์šฉ (๋Œ€์•ˆ)

    • Nginx์™€ ๊ฐ™์€ ์›น ์„œ๋ฒ„์—์„œ TLS๋ฅผ ์„ค์ •ํ•ด WebSocket์„ย wss://๋กœ ๋ณดํ˜ธํ•  ์ˆ˜๋„ ์žˆ์Œ.

3.4 JWT๋ฅผ ์‚ฌ์šฉํ•œ WebSocket ์ธ์ฆ ๊ณผ์ •

3.4.1 ์ดˆ๊ธฐ ์—ฐ๊ฒฐ ์‹œ ํ† ํฐ ์ „์†ก
  • WebSocket์€ HTTP ํ•ธ๋“œ์…ฐ์ดํฌ๋ฅผ ํ†ตํ•ด ์—ฐ๊ฒฐ์„ ์„ค์ •ํ•˜๋ฏ€๋กœ, ์ด ๊ณผ์ •์—์„œ JWT ํ† ํฐ์„ ํ•จ๊ป˜ ์ „์†กํ•˜์—ฌ ์„œ๋ฒ„๊ฐ€ ํด๋ผ์ด์–ธํŠธ๋ฅผ ์‹๋ณ„.

  • WebSocket์˜ย URL ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋‚˜ย ํ—ค๋”์— JWT ํ† ํฐ์„ ํฌํ•จํ•˜์—ฌ ์ „์†ก.

3.4.2 ์„œ๋ฒ„์—์„œ JWT ์ธ์ฆ ๋ฐ ์‹๋ณ„
  • ์„œ๋ฒ„๋Š” ํ•ธ๋“œ์…ฐ์ดํฌ ์š”์ฒญ์— ํฌํ•จ๋œ JWT ํ† ํฐ์„ ํ™•์ธํ•˜๊ณ , ์œ ํšจํ•œ ๊ฒฝ์šฐ WebSocket ์—ฐ๊ฒฐ์„ ํ—ˆ์šฉ.

  • ์„œ๋ฒ„๋Š” JWT ํ† ํฐ์„ ๊ฒ€์ฆํ•˜์—ฌ ํ•ด๋‹น ์‚ฌ์šฉ์ž์˜ **์‹๋ณ„ ์ •๋ณด(์˜ˆ: user ID)**๋ฅผ ์ถ”์ถœํ•˜๊ณ , ์ดํ›„ ํด๋ผ์ด์–ธํŠธ์™€์˜ ํ†ต์‹ ์— ์‚ฌ์šฉ.

์˜ˆ์‹œ ์ฝ”๋“œ
const jwtToken = "your-jwt-token"; //๋Œ€์ถฉ ํด๋ผ์—์„œ ์ €์žฅ์ค‘์ธ ํ† ํฐ

// WebSocket ์—ฐ๊ฒฐ ์‹œ ํ† ํฐ์„ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํฌํ•จํ•˜์—ฌ ์ „์†ก
const socket = new WebSocket(`ws://localhost:8080/chat?token=${jwtToken}`);
  • ํด๋ผ์ด์–ธํŠธ๋Š” WebSocket ์—ฐ๊ฒฐ ์‹œ JWT ํ† ํฐ์„ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „์†ก.

  • ์„œ๋ฒ„๋Š”

    • WebSocket ํ•ธ๋“œ์…ฐ์ดํฌ ์š”์ฒญ์—์„œ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌ๋œ JWT ํ† ํฐ์„ ์ถ”์ถœ & ๊ฒ€์ฆ

    • ํ† ํฐ์ด ์œ ํšจํ•˜๋ฉด ํ•ด๋‹น ์‚ฌ์šฉ์ž ์ •๋ณด(userId)๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ฉ”์‹œ์ง€๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ์Œ.

3.5 ์—ฐ๊ฒฐ ์ฒดํฌ & ์žฌ์—ฐ๊ฒฐ ๋ฐฉ์‹

3.5.1 Ping/Pong ๋ฉ”์‹œ์ง€๋ฅผ ํ†ตํ•œ ์—ฐ๊ฒฐ ์ƒํƒœ ํ™•์ธ

WebSocket ํ”„๋กœํ† ์ฝœ์€ ์—ฐ๊ฒฐ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ดย Ping/Pongย ํ”„๋ ˆ์ž„์„ ์ฃผ๊ณ ๋ฐ›๊ธฐ.

  • Ping: ํด๋ผ์ด์–ธํŠธ๋‚˜ ์„œ๋ฒ„์—์„œ ์ฃผ๊ธฐ์ ์œผ๋กœ ๋ณด๋‚ด๋Š” ์—ฐ๊ฒฐ ์ฒดํฌ ๋ฉ”์‹œ์ง€

  • Pong: Ping์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ, ์—ฐ๊ฒฐ์ด ์—ฌ์ „ํžˆ ์œ ํšจํ•˜๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ.

  • ์‚ฌ์šฉ ์‹œ์ : Ping ๋ฉ”์‹œ์ง€๋ฅผ ์ฃผ๊ธฐ์ ์œผ๋กœ ๋ณด๋‚ด๊ณ , ์ผ์ • ์‹œ๊ฐ„ ๋‚ด์— Pong ์‘๋‹ต์„ ๋ฐ›์ง€ ๋ชปํ•˜๋ฉด ์—ฐ๊ฒฐ์ด ๋Š์–ด์ง„ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ.

3.5.2 ์ž๋™ ์žฌ์—ฐ๊ฒฐ ๋ฐฉ์‹
  • WebSocket ์—ฐ๊ฒฐ์ด ๋Š์–ด์กŒ์„ ๋•Œ,ย ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ผ์ • ์‹œ๊ฐ„ ๊ฐ„๊ฒฉ์œผ๋กœ ์ž๋™์œผ๋กœ ์žฌ์—ฐ๊ฒฐ์„ ์‹œ๋„ํ•˜์—ฌ ๋ณต๊ตฌ.

  • ๋ณดํ†ต ์žฌ์—ฐ๊ฒฐ ๊ฐ„๊ฒฉ์„ ์ ์ฐจ ๋Š˜๋ ค๊ฐ€๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•ด ์„œ๋ฒ„์— ๊ณผ๋„ํ•œ ์žฌ์—ฐ๊ฒฐ ์š”์ฒญ์ด ๊ฐ€์ง€ ์•Š๋„๋ก ๊ตฌํ˜„

3.6 Web Workers๋ฅผ ํ™œ์šฉํ•œ ์†Œ์ผ“๊ฐ์ฒด ๊ณต์œ 

3.6.1 ๋ฌธ์ œ์ 

  • ๋ธŒ๋ผ์šฐ์ € ์—ฌ๋Ÿฌ๊ฐœ์˜ ํƒญ์—์„œ ์„œ๋ฒ„์™€ ํ†ต์‹ ํ•˜๋ ค๊ณ  ํ• ๋•Œ๋Š” ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ค‘๋ณต ์†Œ์ผ“์—ฐ๊ฒฐ์ด ํ•„์š”ํ•จ.

  • ๋‹จ์ผ ์†Œ์ผ“ํ†ต์‹  ์—ฐ๊ฒฐ์„ ์œ ์ง€ํ•˜๋Š” ๋ฐฉ๋ฒ•์€?

3.6.2 ๋ฐฉ์‹
  • Web Workers์˜ Shared Worker๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ตฌํ˜„ ๊ฐ€๋Šฅ.

    • Worker Thread์—์„œ ํ†ต์‹ ์„ ๋‹ด๋‹นํ•˜๊ณ  ๋ธŒ๋ผ์šฐ์ € ํƒญ๊ณผ ํ†ต์‹ ์„ ํ•˜๋ฉด ๋ฐ์ดํ„ฐ(๋ฉ”์‹œ์ง€) ๊ณต์œ 

ws_sw_bc
์ฐธ๊ณ  :ย https://pike96.com/posts/websocket-sharedworker-broadcastchannel/

3.6.3 ์˜ˆ์‹œ

Shared Worker์ฝ”๋“œ

const socket = new WebSocket('wss://example.com/socket');
const clients = []; //๋ธŒ๋ผ์šฐ์ € ํƒญ๋“ค

// WebSocket ๋ฉ”์‹œ์ง€ ์ˆ˜์‹  ์‹œ ์—ฐ๊ฒฐ๋œ ๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ „์†ก
socket.onmessage = (event) => {
  clients.forEach((port) => port.postMessage(event.data));
};

// ์ƒˆ ํด๋ผ์ด์–ธํŠธ(ํƒญ) ์—ฐ๊ฒฐ ์‹œ
onconnect = (event) => {
  const port = event.ports[0];
  clients.push(port);

  // ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์‹ ํ•ด WebSocket์œผ๋กœ ์ „์†ก
  port.onmessage = (e) => {
    socket.send(e.data);
  };

  // ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ์ด ์ข…๋ฃŒ๋˜๋ฉด ๋ฐฐ์—ด์—์„œ ์ œ๊ฑฐ
  port.onclose = () => {
    clients.splice(clients.indexOf(port), 1);
  };
};

๋ฉ”์ธ์“ฐ๋ ˆ๋“œ(๋ธŒ๋ผ์šฐ์ € ํƒญ)

// SharedWorker์— ์—ฐ๊ฒฐ
const worker = new SharedWorker('sharedWorker.js');
worker.port.start(); // ํฌํŠธ ํ™œ์„ฑํ™”

// SharedWorker๋กœ๋ถ€ํ„ฐ ๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์‹ ํ•ด ์ถœ๋ ฅ
worker.port.onmessage = (event) => {
  console.log('์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ๋ฉ”์‹œ์ง€:', event.data);
};

// ๋ฉ”์‹œ์ง€๋ฅผ SharedWorker๋กœ ์ „์†ก (SharedWorker๊ฐ€ WebSocket์„ ํ†ตํ•ด ์„œ๋ฒ„๋กœ ์ „๋‹ฌ)
function sendMessage(message) {
  worker.port.postMessage(message);
}

3.6.4 ์ฃผ์˜์‚ฌํ•ญ
  • ๋ธŒ๋ผ์šฐ์ € ํ˜ธํ™˜์„ฑ ์ด์Šˆ ๋Œ€์•ˆ ํ•„์š”

  • ํ†ต์‹  ์‹œ๊ฐ„ ์ธก์ • ๋น„๊ต ํ•„์š”

  • ํƒญ์ด ํ•˜๋‚˜์ผ๋•Œ ๋Š” ์ผ๋ฐ˜ ์†Œ์ผ“์—ฐ๊ฒฐ, ํƒญ์ด ์—ฌ๋Ÿฌ๊ฐœ์ผ๋•Œ๋Š” Shared Worker๋กœ ๊ตฌํ˜„?


4. socket.io ์‚ฌ์šฉ ์˜ˆ์‹œ

  • socket.io๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ”๋‹๋ผ WebSocket ์ฝ”๋“œ๋ณด๋‹ค ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Œ.

  • ๋‹ค์Œ์€ ๋™์ผํ•œ ๊ธฐ๋Šฅ์„ย socket.io๋กœ ๊ตฌํ˜„ํ•œ ์˜ˆ.

4.1 ์„œ๋ฒ„ ์ฝ”๋“œ (socket.io)

const io = require('socket.io')(3000, {
  cors: {
    origin: "http://localhost:3001",
    methods: ["GET", "POST"]
  }
});

io.on('connection', (socket) => {
  socket.on('draw', (data) => {
    socket.broadcast.emit('draw', data);
  });
});

4.2 ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ (React)

import React, { useEffect, useRef } from 'react';
import io from 'socket.io-client';

const Canvas = () => {
  const canvasRef = useRef(null);
  const socketRef = useRef(null);

  useEffect(() => {
    socketRef.current = io('http://localhost:3000');
    socketRef.current.on('draw', ({ x, y }) => {
      draw(x, y);
    });
    return () => socketRef.current.disconnect();
  }, []);

  const draw = (x, y) => {
    const canvas = canvasRef.current;
    const ctx = canvas.getContext('2d');
    ctx.fillStyle = 'black';
    ctx.fillRect(x, y, 2, 2);
  };

  const handleMouseMove = (event) => {
    const x = event.clientX;
    const y = event.clientY;
    draw(x, y);
    socketRef.current.emit('draw', { x, y });
  };

  return <canvas ref={canvasRef} width={800} height={600} onMouseMove={handleMouseMove} />;
};

export default Canvas;