3 ๋ถ„ ์†Œ์š”

Socket IO ๐Ÿ™€

Socket?

  • ์†Œ์ผ“ โ†’ ํ”„๋กœํ† ์ฝœ, ip์ฃผ์†Œ, ํฌํŠธ๋„˜๋ฒ„๋กœ ์ •์˜.

  • ๋–จ์–ด์ ธ ์žˆ๋Š” ๋‘ ํ˜ธ์ŠคํŠธ๋ฅผ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ๋„๊ตฌ๋กœ์จ ์ธํ„ฐํŽ˜์ด์Šค ์—ญํ• .

  • ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ  ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ๊ตฌ์กฐ์ฒด๋กœ ์†Œ์ผ“์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ ํ†ต๋กœ๊ฐ€ ๋งŒ๋“ค์–ด ์ง„๋‹ค.

  • ์†Œ์ผ“์˜ ์—ญํ• ์— ๋”ฐ๋ผ ํด๋ผ์ด์–ธํŠธ ์†Œ์ผ“, ์„œ๋ฒ„์†Œ์ผ“์œผ๋กœ ๊ตฌ๋ถ„๋œ๋‹ค.

Socket IO : Websocket์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์‹ค์‹œ๊ฐ„ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์œ„ํ•œ JavaScript ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค. ์›น ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ๊ฐ„์˜ ์‹ค์‹œ๊ฐ„ ์–‘๋ฐฉํ–ฅ ํ†ต์‹ ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” Node.js์˜ ๋ชจ๋“ˆ์ด๋‹ค.

โ— ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ : ์žฅ์น˜์˜ ์šด์˜ ์ฒด์ œ(OS)์—์„œ ๋กœ์ปฌ๋กœ ์‹คํ–‰๋˜๋Š” ์ปดํ“จํ„ฐ ๊ธฐ๋ฐ˜ ์†Œํ”„ํŠธ์›จ์–ด ํ”„๋กœ๊ทธ๋žจ๊ณผ ๋‹ฌ๋ฆฌ ์›น ์„œ๋ฒ„์—์„œ ์‹คํ–‰๋˜๋Š” ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ ์†Œํ”„ํŠธ์›จ์–ด

โ— Websocket : ๋ฐ์ดํ„ฐ๊ฐ€ ๋ˆ„๋ฝ๋˜์ง€ ์•Š๊ฒŒํ•˜๋Š” tcp๊ธฐ๋ฐ˜์˜ ์–‘๋ฐฉํ–ฅํ†ต์‹ ์„ ์ œ๊ณตํ•˜๋Š” ์ปดํ“จํ„ฐ ํ”„๋กœํ† ์ฝœ




์‚ฌ์šฉ ์ด์œ 

Http ํ†ต์‹ ์€ ๋‹จ๋ฐฉํ–ฅ ๋ฐฉ์‹์ด๊ณ  ์—ฐ๊ฒฐ์ด ์œ ์ง€๊ฐ€ ์•ˆ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋งค๋ฒˆ ์—…๋ฐ์ดํŠธ ์œ /๋ฌด๋ฅผ ํ™•์ธํ•˜๊ธฐ์œ„ํ•ด์„œ ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ถˆ๋Ÿฌ์™€์•ผ ํ•œ๋‹ค.๊ทธ๋ฆฌ๊ณ  ์š”์ฒญ์„ ํ• ๋•Œ ๋งˆ๋‹ค ์ „์ฒด ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ฒŒ ๋˜์–ด์žˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋ฒ„์— ๋งŽ์€ ๋ถ€ํ•˜๊ฐ€ ์ƒ๊ธฐ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค

ํ•˜์ง€๋งŒ ์›น์†Œ์ผ“์€ ์–‘๋ฐฉํ–ฅ ํ†ต์‹ ์„ ์ง€์›ํ•˜๊ฒŒ ๋˜์–ด์žˆ๊ณ  ๋˜ ์„œ๋ฒ„์™€์˜ ์—ฐ๊ฒฐ์ด ์œ ์ง€๊ฐ€ ๋œ ์ƒํƒœ์—์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ์˜ค๊ฐˆ์ˆ˜์žˆ๊ฒŒ ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์ „์†ก์ด ๊ฐ€๋Šฅํ•ด์ง€๊ฒŒ ๋œ๋‹ค. ์ด๋Ÿด ๋•Œ Websocket์„ ์ด์šฉํ•œ๋‹ค.

(์š”์•ฝํ•˜์ž๋ฉด ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์—ฐ๊ฒฐ๋˜์žˆ๋Š” ์ƒํƒœ๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉ)




WebSocket vs socket.io

์‚ฌ์‹ค ์• ์ดˆ์— ๋‘˜์€ ๋‹ค๋ฅธ ๊ฐœ๋…์ด๋‹ค.

์›น์†Œ์ผ“์€ ์–‘๋ฐฉํ–ฅ ์†Œํ†ต์„ ์œ„ํ•œ ํ”„๋กœํ† ์ฝœ์ด๋‹ค. ํ”„๋กœํ† ์ฝœ์€ ์‰ฝ๊ฒŒ ๋งํ•˜์ž๋ฉด ์„œ๋กœ ๋‹ค๋ฅธ ์ปดํ“จํ„ฐ๋ผ๋ฆฌ ์†Œํ†ตํ•˜๊ธฐ ์œ„ํ•œ ์•ฝ์†์ด๋‹ค.

๋ฐ˜๋ฉด์—, socket.io๋Š” ์–‘๋ฐฉํ–” ํ†ต์‹ ์„ ํ•˜๊ธฐ์œ„ํ•ด ์›น์†Œ์ผ“ ๊ธฐ์ˆ ์„ ํ™œ์šฉํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค. ์–ด์ฐŒ๋ณด๋ฉด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์™€ jQuery์˜ ๊ด€๊ณ„์™€ ๋น„์Šทํ•˜๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— socket.io๊ฐ€ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋”๋ผ๋„ ์•ฝ๊ฐ„ ๋Š๋ฆฌ์ง€๋งŒ, ๋งŽ์€ ํŽธ์˜์„ฑ์„ ์ œ๊ณตํ•œ๋‹ค. ๋˜ํ•œ Java, C++, Python ๋“ฑ ์—ฌ๋Ÿฌ ์–ธ์–ด๋“ค์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋˜ํ•œ ์ง€์›๋ฉ๋‹ˆ๋‹ค.


WebSocket

  • HTML5 ์›น ํ‘œ์ค€ ๊ธฐ์ˆ 
  • ๋งค์šฐ ๋น ๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋ฉฐ ํ†ต์‹ ํ•  ๋•Œ ์•„์ฃผ ์ ์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ด์šฉํ•จ
  • ์ด๋ฒคํŠธ๋ฅผ ๋‹จ์ˆœํžˆ ๋“ฃ๊ณ , ๋ณด๋‚ด๋Š” ๊ฒƒ๋งŒ ๊ฐ€๋Šฅํ•จ


Socket.io

  • ํ‘œ์ค€ ๊ธฐ์ˆ ์ด ์•„๋‹ˆ๋ฉฐ, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž„
  • ์†Œ์ผ“ ์—ฐ๊ฒฐ ์‹คํŒจ ์‹œ fallback์„ ํ†ตํ•ด ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ์•Œ์•„์„œ ํ•ด๋‹น ํด๋ผ์ด์–ธํŠธ์™€ ์—ฐ๊ฒฐ์„ ์‹œ๋„ํ•จ
  • ๋ฐฉ ๊ฐœ๋…์„ ์ด์šฉํ•ด ์ผ๋ถ€ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๋Š” ๋ธŒ๋กœ๋“œ์บ์ŠคํŒ…์ด ๊ฐ€๋Šฅํ•จ


์„œ๋ฒ„์—์„œ ์—ฐ๊ฒฐ๋œ ์†Œ์ผ“(์‚ฌ์šฉ์ž)๋“ค์„ ์„ธ๋ฐ€ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•ด์•ผํ•˜๋Š” ์„œ๋น„์Šค์ธ ๊ฒฝ์šฐ์—๋Š” Broadcasting ๊ธฐ๋Šฅ์ด ์žˆ๋Š” socket.io์„ ์“ฐ๋Š”๊ฒŒ ์œ ์ง€๋ณด์ˆ˜ ์ธก๋ฉด์—์„œ ํ›จ์”ฌ ์ด์ ์ด ๋งŽ๋‹ค.

๋ฐ˜๋ฉด ๊ฐ€์ƒํ™”ํ ๊ฑฐ๋ž˜์†Œ๊ฐ™์ด ๋ฐ์ดํ„ฐ ์ „์†ก์ด ๋งŽ์€ ๊ฒฝ์šฐ์—๋Š” ๋น ๋ฅด๊ณ  ๋น„์šฉ์ด ์ ์€ ํ‘œ์ค€ WebSocket์„ ์ด์šฉํ•˜๋Š”๊ฒŒ ๋ฐ”๋žŒ์งํ•˜๋‹ค.

์‹ค์ œ๋กœ ์—…๋น„ํŠธ๋‚˜ ๋ฐ”์ด๋‚ธ์Šค ์†Œ์ผ“ API๋ฅผ ์‚ฌ์šฉํ•ด๋ณด๋ฉด ์ •๋ง ์—„์ฒญ๋‚˜๊ฒŒ ๋งŽ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด์˜จ๋‹ค.




๊ตฌํ˜„ํ•˜๊ธฐ

Back

const realTimeChat = io => {
  io.on('connection', socket => {
    socket.on('joinRoom', ({ username, room }) => {
      const user = userJoin(socket.id, username, room);
      insertUesrInfo(user);
      socket.join(user.room);
      socket.emit('message', formatMessage(botName, `${user.username}๋‹˜ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ˜€`));
      socket.broadcast
        .to(user.room)
        .emit('message', formatMessage(botName, `${user.username}๋‹˜์ด ์ฐธ๊ฐ€ํ•˜์…จ์Šต๋‹ˆ๋‹ค.`));
      io.to(user.room).emit('roomUsers', {
        room: user.room,
        users: getRoomUsers(user.room),
      });
    });

    socket.on('chatMessage', msg => {
      const user = getCurrentUser(socket.id);
      insertMsg(msg, user);
      io.to(user.room).emit('message', formatMessage(user.username, msg));
    });

    socket.on('disconnect', () => {
      const user = userLeave(socket.id);
      if (user) {
        io.to(user.room).emit(
          'message',
          formatMessage(botName, `${user.username}๋‹˜์ด ๋‚˜๊ฐ€์…จ์Šต๋‹ˆ๋‹ค.`)
        );
        io.to(user.room).emit('roomUsers', {
          room: user.room,
          users: getRoomUsers(user.room),
        });
      }
      user && deleteUserInfo(user);
    });
  });
};

export default realTimeChat;


Front

    <script>
      const chatForm = document.getElementById('chat-form');
      const chatMessages = document.querySelector('.chat-messages');
      const roomName = document.getElementById('room-name');
      const userList = document.getElementById('users');

      const { username, room } = Qs.parse(location.search, {
        ignoreQueryPrefix: true,
      });

      var socket = io.connect('https://www2.wecode.buzzntrend.com');

      socket.emit('joinRoom', { username, room });

      socket.on('roomUsers', ({ room, users }) => {
        roomName.innerText = room;
        userList.innerHTML = '';
        users.forEach((user) => {
          const li = document.createElement('li');
          li.innerText = user.username;
          userList.appendChild(li);
        });
      });

      socket.on('message', (message) => {
        outputMessage(message);
        chatMessages.scrollTop = chatMessages.scrollHeight;
      });

      chatForm.addEventListener('submit', (e) => {
        e.preventDefault();
        let msg = e.target.elements.msg.value;
        msg = msg.trim();
        if (!msg) {
          return false;
        }
        socket.emit('chatMessage', msg);
        e.target.elements.msg.value = '';
        e.target.elements.msg.focus();
      });

      function outputMessage(message) {
        const div = document.createElement('div');
        div.classList.add('message');
        const p = document.createElement('p');
        p.classList.add('meta');
        p.innerText = message.username;
        p.innerHTML += `<span>${message.time}</span>`;
        div.appendChild(p);
        const para = document.createElement('p');
        para.classList.add('text');
        para.innerText = message.text;
        div.appendChild(para);
        document.querySelector('.chat-messages').appendChild(div);
      }
    </script>


์‹ค์ œ ๊ตฌํ˜„์˜์ƒ


socket-1


๊ฐ๊ฐ ์ƒ์„ฑ๋œ ๋ฐฉ์•ˆ์˜ ๋ชจ๋“  ๋Œ€ํ™”๋‚ด์šฉ๋“ค์€ Mongo DB์— ์ €์žฅ๋˜๋„๋ก ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

์—ญ์‹œ ๋™์ ์ธ๊ฑธ ํ•˜๋‹ˆ๊น ๋„ˆ๋ฌด ์žฌ๋ฐŒ๋‹ค..




์ฐธ๊ณ 

์œ„์˜ ์ฝ”๋“œ๋Œ€๋กœ ํ•œ๋‹ค๋ฉด ๋กœ๋“œ๋ฐธ๋Ÿฐ์‹ฑ์— ์˜ํ•ด ์„œ๋ฒ„๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ ์ƒ์„ฑ๋ ์‹œ

์œ ์ €๋“ค๋ผ๋ฆฌ ์ฑ„ํŒ…์ด ๋ถˆ๊ฐ€๋Šฅํ•  ๊ฒƒ์ด๋‹ค.

ex. ๋‚˜๋„ A๋ฐฉ์— ๋“ค์–ด๊ฐ€๊ณ  ๋‹ค๋ฅธ์‚ฌ๋žŒ๋„ A๋ฐฉ์— ๋“ค์–ด๊ฐ”๋Š”๋ฐ ์†Œํ†ต์ด์•ˆ๋Œ

๊ทธ๋Ÿด๋•Œ ํ•„์š”ํ•œ๊ฒƒ์ด socket.io-redis์ด๋‹ค.

redis adapter๋Š” ๋Œ€์ถฉ ์•„๋ž˜๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด ๋™์ž‘ํ•œ๋‹ค.


socket-1


๊ธฐ๋ณธ์ ์œผ๋กœ redis์˜ pub/sub๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•œ ๊ฒƒ์ธ๋ฐ ๊ฐ„๋‹จํžˆ ๋งํ•˜์ž๋ฉด

์ฑ„๋„์„ ๊ตฌ๋…ํ•œ subscribe์—๊ฒŒ ๋ชจ๋“  ๋ฉ”์„ธ์ง€๋ฅผ ์ „์†ก ํ•˜๋Š”๊ฒƒ์ด๋‹ค.


redis-5


redis๋ฅผ ํ†ตํ•ด ์‹คํ—˜์„ ํ•ด๋ดค๋Š”๋ฐ

A๋ฅผ ๊ตฌ๋…ํ•œ ํ„ฐ๋ฏธ๋„์—๋Š” A์˜ ๋ฉ”์„ธ์ง€๋งŒ B๋ฅผ ๊ตฌ๋…ํ•œ ํ„ฐ๋ฏธ๋„์—๋Š” B์˜ ๋ฉ”์„ธ์ง€๋งŒ ๋‚˜์˜ค๋Š”๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.


์ด์ œ ์ด๊ฒƒ์„ ๋‚ด๊ฐ€๋งŒ๋“  socket.io์„œ๋ฒ„์— ํ™œ์šฉํ•ด๋ณด์ž.

์ •๋ง ๊ฐ„๋‹จํ•˜๋‹ค

const redisAdapter = require("socket.io-redis");

io.adapter(redisAdapter({ host: "localhost", port: 6379 }));

์ด๊ฒƒ๋งŒ ์„ ์–ธํ•ด์ฃผ๋ฉด ์•Œ์•„์„œ to(โ€œ๋ฐฉ์ด๋ฆ„โ€).emit์— redis์˜ pub/sub๊ธฐ๋Šฅ์ด ๋ถ€์ฐฉ๋œ๋‹ค.

(๋ง๊ทธ๋Œ€๋กœ ์–ด๋Žํ„ฐ๋‹ค..์ •๋ง ํŽธ๋ฆฌํ•จ)


*****************************์ค‘์š”์‚ฌํ•ญ*****************************


โ€˜๋งŒ์•ฝ redis๊ฐ€ ์ฃฝ์–ด๋ฒ„๋ฆฌ๋ฉดโ€™๋ผ๋Š” ๊ฐ€์ •์˜ ์˜ˆ์™ธ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ์ง€ ์•Š๋Š”๋‹ค๋ฉด server ๋˜ํ•œ ์ฃฝ์–ด๋ฒ„๋ฆฌ๊ฒŒ๋œ๋‹ค.


io.of('/').adapter.on('error', error => {
    console.log('redisAdapter: ', error);
  });

์œ„์™€๊ฐ™์ด redis๊ฐ€ ์ฃฝ์—ˆ์„๋•Œ์˜ ์˜ˆ์™ธ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ค˜์„œ server๋Š” ๊บผํŠธ๋ฆฌ์ง€ ์•Š๋„๋กํ•˜์ž

(๋ฌผ๋ก  ์ด๋ ‡๊ฒŒ ๋์„๋• redis๊ฐ€ ์‚ด์•„๋‚ ๋•Œ๊นŒ์ง€ ํ˜„์žฌ์˜ ์„œ๋ฒ„์— ์žˆ๋Š” ํด๋ผ์ด์–ธํŠธ๋ผ๋ฆฌ๋งŒ ์ฑ„ํŒ…์ด ๊ฐ€๋Šฅํ•˜๋‹ค)


์ฐธ๊ณ ์‚ฌํ•ญ์˜ socket.io-redis, ์—๋Ÿฌ์ฒ˜๋ฆฌ ๋ชจ๋‘ ๊ตฌ๋ฌธ๋ฒ•์ด๋‹ค.

ํ˜„์žฌ๋Š” @socket.io/redis-adapter๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ๋ฐ”๋€Œ์—ˆ๋‹ค.

๋‚ด๊ฐ€ ๊ตฌ๋ฌธ๋ฒ•์„ ์“ด ์ด์œ ๋Š” ์‚ฌ์šฉํ•˜๊ธฐ์—๋„ ํŽธํ•˜๊ณ  ์ง๊ด€์ ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

https://www.opensourceagenda.com/projects/socketio-redis/versions

https://socket.io/docs/v4/redis-adapter/

asdasdasdasds asdasdasd

์—…๋ฐ์ดํŠธ: