๐ŸงSocket.io ๋ฅผ ์ ์šฉํ•œ Real-Time Chat

๐ŸŒˆSocket.io

์ง€๋‚œ ์ฃผ ์‹ ์ • ์—ฐํœด ํฌํ•จํ•œ ๊ธฐ๊ฐ„๋™์•ˆ Socket.io ๋ฅผ ์–ด๋–ป๊ฒŒ ๋‚ด ์ฝ”๋ชฝ์–ด์Šค ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•ด ๋ณผ๊นŒ ๊ถ๋ฆฌํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ๊ณ ,

์ผ์š”์ผ๋‚  ์™„์ „ํ•œ ๋งˆ๋ฌด๋ฆฌ๋Š” ์•„๋‹ˆ์ง€๋งŒ ๋งŒ๋“ค์–ด ๋ณผ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

์˜จ์ „ํžˆ ๋‚ด ๋จธ๋ฆฌ์—์„œ ๋‚˜์˜จ ๊ฒƒ์ด ์•„๋‹ˆ๊ณ  ์œ ํŠœ๋ธŒ์— ๋‚˜์˜ค๋Š” ์™ธ๊ตญ์ธ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ŠคํŠธ๋ฆฌ๋ฐํ•˜๋Š” ๊ธด ์‹œ๊ฐ„์˜ ํŠœํ† ๋ฆฌ์–ผ ์˜์ƒ์„ ๋‹ค์„ฏ ์ฐจ๋ก€ ๋ณด๋ฉฐ,

์ฝ”๋“œ๋ฅผ ์ณ ๊ฐ€๋ฉฐ ์ดํ•ดํ•ด ๋ณด๋‹ค๊ฐ€ ๋งˆ์ง€๋ง‰์— ๋‚ด๊ฐ€ ์ดํ•ดํ•œ ๋‚ด์šฉ์„ ๋ฐ”ํƒ•์œผ๋กœ Socket.io ๊ณต์‹๋ฌธ์„œ์™€ ์‹ค์ œ ๋‚ด ์ฝ”๋ชฝ์–ด์Šค ํ”„๋กœ์ ํŠธ์— ์ง์ ‘ ๋‚ด๊ฐ€ ์ดํ•ดํ•œ ๋ฐ”๋ฅผ

์ฃผ์„์œผ๋กœ ์ž‘์„ฑํ•ด๊ฐ€๋ฉฐ ์ฝ”๋“œ๋ฅผ ์™„์„ฑํ–ˆ๋‹ค.

๋ณ„๋„๋กœ ์ฝ”๋“œ๋ฅผ ์ณ ๊ฐ€๋ฉฐ ํ…Œ์ŠคํŠธ ํ–ˆ์„ ๋• ์ž˜ ๋˜์—ˆ์ง€๋งŒ ์ด๊ฑธ ๋‚ด ํ”„๋กœ์ ํŠธ์— ์ด์‹ํ•ด์„œ ์‹œ๋„ํ•ด ๋ณด๋ คํ•˜๋‹ˆ ์ž˜ ์•ˆ๋˜์—ˆ์—ˆ๋Š”๋ฐ,

์ด๋•Œ ์—๋Ÿฌ ํ•ธ๋“ค๋ง ์ด๋‚˜ ๊ฒ€์ƒ‰ํ•˜๋Š” ๋ฒ• ๊ทธ๋ฆฌ๊ณ  socket.io ์˜ ํด๋ผ์ด์–ธํŠธ - ์„œ๋ฒ„ ๊ฐ„์˜ ํ†ต์‹  ๋ฐฉ๋ฒ•, ์ด๋ฒคํŠธ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฒ• ๋“ฑ์— ๋Œ€ํ•ด ์ ˆ๋ฐ˜ ์ด์ƒ์€

์ต์ˆ™ํ•ด์กŒ๋‹ค.

๋งŒ๋“ค์–ด์„œ ๋!

์ด ์•„๋‹ˆ๋ผ, ์ด์ œ ๋‚ด ํ”„๋กœ์ ํŠธ์— ๋‚˜๋ฅผ ์†Œ๊ฐœ ํ•˜๋Š” ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค ๋•Œ๊ฐ€ ๋˜์—ˆ๋Š”๋ฐ ๋ฐ”๋กœ.

์ด ์›นํŽ˜์ด์ง€๋ฅผ ๊ณต์œ ํ•˜๋ฉด์„œ ๋‚˜๋ฅผ ์†Œ๊ฐœ ํ•  ๋•Œ ์‹œ์ฒญ์ž๊ฐ€ ํ•ด๋‹น ์†Œ๊ฐœ ํŽ˜์ด์ง€์—์„œ ๋‚ด ์†Œ๊ฐœ๋ฅผ ๋ณด๋ฉด์„œ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ฑ„ํŒ…์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ

์žฌ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์ด ๋‚˜์˜ ๋ชฉํ‘œ์ด๋‹ค.

๐ŸŽ‡ComongUS ์— ์ ์šฉํ•œ ๋ชจ์Šต - ๋ฉ”์ธ ๋ฃจํŠธ(root)

mainchat

๋ฉ”์ธ์€ localhost:3000 ์œผ๋กœ ์ฒ˜์Œ ํด๋ผ์ด์–ธํŠธ์˜ ํ™”๋ฉด์ด ๋ Œ๋”๋ง ๋œ๋‹ค.

chatterbox ๋ฅผ ๋ฆฌ์•กํŠธ ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค.

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์„œ๋ฒ„๋„ ์ง์ ‘ ๊ตฌํ˜„ํ–ˆ๋‹ค. (localhost:4000)

const express = require('express')
const cors = require('cors')
const app = express()
const bodyParser = require('body-parser')
const jsonParser = bodyParser.json()
const port = 4000

let data = {
  results: [
    {
      username: 'FengSU๐Ÿง',
      text: 'ComongUS with Express.js๐ŸŒˆ',
      roomname: 'MyROOM๐Ÿ–๐Ÿผ',
      date: new Date().toLocaleString(),
    },
  ],
}

app.use(cors())

app.use(jsonParser)

app.get('/messages', (req, res) => {
  res.status(200).send(data)
})

app.post('/messages', (req, res) => {
  console.log(req.body)
  data.results.push(req.body)
  res.status(201).send(req.body)
})

app.listen(port, () => {
  console.log(`COMONGUS app listening at http://localhost:${port} ๐Ÿผ`)
})

๋‹ค๋งŒ socket.io ๋กœ ๊ตฌํ˜„ํ•œ ๋ฆฌ์–ผํƒ€์ž„ ์ฑ„ํŒ…์˜ ์„œ๋ฒ„๋Š” 5000๋ฒˆ ์ด๋‹ค. ํ•˜๋‚˜๋กœ ํ•ฉ์น˜๋Š” ์‹œ๋„๋Š” ์•„์ง ํ•˜์ง€ ์•Š์•˜๋‹ค.

ํ•˜์ง€๋งŒ ๊ฐ€๋Šฅํ•œ ๊ฑฐ ๊ฐ™๋‹ค.

express.Router() ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ณ„๋„๋กœ routes.js ํŒŒ์ผ์„ ์ƒ์„ฑํ•ด์„œ ์ด ํŒŒ์ผ ๋‚ด์—์„œ ์—”๋“œํฌ์ธํŠธ์— ๋”ฐ๋ผ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌ ํ•ด ์ค„์ง€๋ฅผ ๋ถ„๊ธฐํ•  ์ˆ˜ ์žˆ๋‹ค.

๐ŸŽ‡๋ฉ”์ธ ๋ฃจํŠธ์˜ CSS

์œ„์˜ ๊ทธ๋ฆผ์„ ๋ณด๋ฉด ๋ถ„ํ™๋ถ„ํ™ํ•˜๊ฒŒ ๋ฐ˜์ง๊ฑฐ๋ฆฌ๋Š” ํ…์ŠคํŠธ๋ฅผ ํด๋ฆญํ•˜๋ฉด ๋ฆฌ์–ผ ํƒ€์ž„ ์ฑ„ํŒ… ๋ฐฉ์œผ๋กœ ๋„˜์–ด๊ฐ€๊ฒŒ ๋œ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์ € ๋ถ„ํ™๋ถ„ํ™ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ๋ณด๋ ค๊ณ  keyframes ์— ๋Œ€ํ•ด ์ฐพ์•„ ๋ณด์•˜๊ณ  main ์— ํ•ด๋‹นํ•˜๋Š” Home.css ์— ์ž‘์„ฑํ•ด์ฃผ์—ˆ๋Š”๋ฐ..

๋ฌด์ฒ™์ด๋‚˜ ๋Š๋ ค์ง€๋Š” ๊ฒƒ์ด์˜€๋‹ค.

๋Œ€๋žต ์ด๋Ÿฐ ์ฝ”๋“œ์ด๋‹ค..

@-webkit-keyframes neon1 {
  from {
    text-shadow: 0 0 10px #fff, 0 0 20px #fff, 0 0 30px #fff, 0 0 40px #ff1177,
      0 0 70px #ff1177, 0 0 80px #ff1177, 0 0 100px #ff1177, 0 0 150px #ff1177;
  }
  to {
    text-shadow: 0 0 5px #fff, 0 0 10px #fff, 0 0 15px #fff, 0 0 20px #ff1177,
      0 0 35px #ff1177, 0 0 40px #ff1177, 0 0 50px #ff1177, 0 0 75px #ff1177;
  }
}

๊ทธ๋ž˜์„œ ํ˜„์žฌ๋Š” ์ฃผ์„์„ ์ฑ„์›Œ๋†“์€ ์ƒํƒœ์ด๋‹ค.

๐ŸŽ‡Welcome to Real-Time Chat!

setname

๊ทธ๋ ‡๊ฒŒ ํด๋ฆญํ•ด์„œ ๋“ค์–ด๊ฐ€๋ฉด

localhost:3000/rtcjoin ์œผ๋กœ ๊ฒฝ๋กœ๊ฐ€ ํ•˜๋‚˜ ๋” ๋Š˜์–ด๋‚˜๋Š”๋ฐ,

์—ฌ๊ธฐ์„œ roomname ๊ณผ ๋‚ด ๋‹‰๋„ค์ž„์„ ์น˜๊ณ  ๋“ค์–ด๊ฐ€๊ฒŒ ๋œ๋‹ค.

const express = require('express')
const app = express()
const http = require('http')
const socketio = require('socket.io')

const { addUser, removeUser, getUser, getUsersInRoom } = require('./users.js')

const PORT = 5000

const router = require('./router')

const server = http.createServer(app)

const io = socketio(server)

io.on('connection', socket => {
  console.log('a user connected!!๐Ÿผ')
  // ! client side ์—์„œ emit ์œผ๋กœ ๋ณด๋‚ธ ์ด๋ฒคํŠธ 'join' ์„ ๋ฐ›์•„์˜ค๊ฒ ๋‹ค.
  // socket.on("join", (data) => {
  //   console.log(data); // ์˜ค ์ง€์ ธ์Šค.. { name: 'hello', room: 'world' } ๊ฐ€ CLI ์— ์ฐํžŒ๋‹ค.
  // });
  socket.on('join', ({ name, room }, callback) => {
    console.log(name, room)

    const { error, user } = addUser({ id: socket.id, name, room }) // users.js ์—์„œ ํ•จ์ˆ˜๊ฐ€ ๋ฆฌํ„ดํ•˜๋Š” ๊ฒƒ์„ ๋ˆˆ์—ฌ๊ฒจ ๋ณผ๊ฒƒ!

    if (error) return callback(error)
    // !emitted event ๋Š” ๋ฐฑ์—”๋“œ์—์„œ ํ”„๋ก ํŠธ์—”๋“œ๋กœ ๋„˜๊ฒจ์ฃผ๊ธฐ ์œ„ํ•œ ๋ฐฉ์‹ ์ด๊ตฌ๋‚˜!
    socket.emit('message', {
      user: 'admin',
      text: `${user.name}, Welcome to the room ${user.room}.`,
    })
    socket.broadcast
      .to(user.room)
      .emit('message', { user: 'admin', text: `${user.name}, has joined!` })

    socket.join(user.room)

    io.to(user.room).emit('roomData', {
      room: user.room,
      users: getUsersInRoom(user.room),
    })

    callback()
  })
  // ! on event ๋Š” ๋ฐฑ์—”๋“œ์—์„œ์˜ ์ด๋ฒคํŠธ
  socket.on('sendMessage', (message, callback) => {
    const user = getUser(socket.id)

    io.to(user.room).emit('message', { user: user.name, text: message })
    io.to(user.room).emit('roomData', {
      room: user.room,
      users: getUsersInRoom(user.room),
    })

    callback()
  })
  socket.on('disconnect', () => {
    // console.log("user disconnected!!๐Ÿ˜ข");
    const user = removeUser(socket.id)

    if (user) {
      io.to(user.room).emit('message', {
        user: 'admin',
        text: `${user.name} has left.`,
      })
    }
  })
})

app.use(router)

server.listen(PORT, () => {
  console.log(`Server HAS Started on port ${PORT}`)
})

socket.io ๋ฅผ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” express ์™€ http ๋ชจ๋“ˆ์„ ๋ชจ๋‘ ์‚ฌ์šฉํ•ด์•ผ ํ•œ ๋‹ค๋Š” ์ ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค.

๋‚ด๊ฐ€ ๋งŒ๋“  ์„œ๋ฒ„๋Š” express ๋กœ (localhost:5000),

socket.io ๋ฅผ ๋ฐ›์•„์˜ค๊ธฐ ์œ„ํ•œ ์„œ๋ฒ„๋Š” http.createServer ๋กœ ๋‚ด๋ถ€ ์ธ์ž๋Š” express() ๋ฅผ ๋ฐ›์•„์„œ ๋งŒ๋“ค๊ฒŒ ๋œ๋‹ค.

๐ŸŽ‡Real-Time Chat!

rtc1

๋ฐฉ ์ด๋ฆ„๊ณผ ์ ‘์†ํ–ˆ๋‹ค๋Š” ๋ฉ”์‹œ์ง€๊ฐ€ ๋œจ๊ณ , ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ์ ‘์† ํ•  ๋•Œ ๋ฉ”์‹œ์ง€๊ฐ€ ๋œฌ๋‹ค.

broadcast, emit, on ๋“ฑ์— ๋Œ€ํ•ด ์™„์ „ํžˆ ์Šต๋“ํ•˜์ง€๋Š” ๋ชปํ–ˆ์ง€๋งŒ ๋‹ค์‹œ ๋„์ „ํ•  ๋•Œ ํ›จ์”ฌ ๋” ํšจ๊ณผ์ ์œผ๋กœ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ž์‹ ๊ฐ์ด ์ƒ๊ฒผ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ,

์—ฌ๋Ÿฌ ํด๋ผ์ด์–ธํŠธ๋ฅผ ๋™์‹œ์— ์—ด๊ณ  ๊ฐ™์€ ์ด๋ฆ„์˜ ๋ฐฉ์— ์ ‘์†ํ•˜๋ฉด ์•„๋ž˜์˜ ํ™”๋ฉด์„ ๋ณผ ์ˆ˜ ์žˆ๊ณ ,

๋ฐฉ์— ์ ‘์†ํ•œ ์‚ฌ๋žŒ๋“ค์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ณ , ํ•ด๋‹น ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ ‘์†์„ ํ•ด์ œ ํ•˜๋ฉด broadcast ๋ฅผ ํ†ตํ•ด ๋ฐฉ์— ๋‚จ์€ ๋‹ค๋ฅธ ํด๋ผ์ด์–ธํŠธ๋“ค์€

ํ•ด์ œํ•œ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ˆ„๊ตฌ์ธ์ง€ ๋ฉ”์‹œ์ง€๋ฅผ ๋ Œ๋”ํ•จ์œผ๋กœ์จ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

rtc2

๐ŸŽ‡๊ฐœ์„ ํ•  ์ 

์ ‘์†์„ ํ•ด์ œํ•œ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฉ”์‹œ์ง€ ์ƒ์—์„œ๋Š” ํ•ด์ œ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์ง€๋งŒ,

ํŒŒ๋ž€๋ถˆ์˜ ์ƒํƒœ์™€ ํ•ด๋‹น ํด๋ผ์˜ ์œ ์ €์ด๋ฆ„์„ ์ง€์šฐ๊ฒŒ๋” ๊ตฌํ˜„ํ•ด๋ด์•ผ ๊ฒ ๋‹ค.


Written by@[DotoriMook]
ํ”„๋ก ํŠธ์—”๋“œ ์ฃผ๋‹ˆ์–ด ๊ฐœ๋ฐœ์ž ๋„ํ† ๋ฆฌ๋ฌต์˜ ๊ธฐ์ˆ ๊ฐœ๋ฐœ ๋ธ”๋กœ๊ทธ ์ž…๋‹ˆ๋‹ค.

GitHubMediumTwitterFacebook