พัฒนาเว็บแชทด้วย Socket.io + Node.js

Web Development 23 ธันวาคม พ.ศ. 2566 361
Home / Articles / 69

สวัสดีครับ ในบทความนี้ผมจะมาแนะนำการสร้าง Web Chat Application อาศัยเครื่องมือ ได้แก่ Node.js, Express.js, Socket.io  โดย Node.js จะเป็น Server-Side Processing ส่วน Express.js จะเป็นตัว Routing และ Serve หน้าเว็บ EJS Template

EJS

EJS คือ template engine ที่ทำให้เราสามารถเขียนข้อมูลจาก Server-Side ลงไปใน HTML ก่อนที่จะ Serve ให้กับ Client ได้ ลักษณะแบบ Pre-Processing คล้าย PHP คือ หน้าเว็บถูกประมวลผลก่อนแล้วส่งไปให้ Client แบบ HTML ปกติ ไม่จำเป็นต้องมี Node.js อีกตัวที่ทำหน้าที่เป็น Front-end ติดต่อกับ Server

Socket.io

Socket.io เป็น Library ที่ทำให้เราสามารถติดต่อสื่อสารกับ Client ที่กำลังเปิดเว็บไซต์เราได้ โดยที่จะมี Socket.io ทำงานอยู่บน Browser ของ Client ติดต่อกับ Server อยู่ตลอด และในฝั่งของ Server-Side ก็จะต้องมี Socket.io ทำงานอยู่เช่นกัน จึงจะสามารถสร้างการติดต่อระหว่าง Server กับ Client ได้

Socket.io ในฝั่งของ Client จะสามารถ "Emit" หรือส่งข้อมูลต่างๆ ไปหา Server ได้ ส่วน Server ก็มีหน้าที่ broadcast ข้อมูลดังกล่าวกลับไปหา Client ทุกคนที่กำลังเปิดหน้าเว็บอยู่ เราสามารถตั้งเงื่อนไขได้ว่า หาก Server Broadcast มาแล้ว ปรากฏว่าต้นทางต้องการจะส่งมาถึง Username "A" Browser ก็จะรับข้อมูลดังกล่าวมาแสดง หาก Username ของ Client ตรงกับข้อมูลปลายทางที่กำหนดมากับข้อมูล เป็นต้น

Server-Side

const app = express()
const server = http.createServer(app)
const { Server } = require('socket.io')
const io = new Server(server)
app.use(express.static(path.join(__dirname, "/public")))
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'ejs')

server.listen(4000 ,() => {
    console.log('Listening on port 4000...')
})

app.get('/socket.io/socket.io.js', (req, res) => {
	res.sendFile(__dirname + '/node_modules/socket.io/client-dist/socket.io.js');
})
app.get('/chat', (req,res) => {
    res.render('chat')
    res.end()
})
io.on('connection', (socket) => {
    console.log('New client connected!')
    socket.on('chat_message', (data) => {
        io.emit('chat_message', {
            msg: data.msg
        })
    })
    socket.on('disconnected', (socket) => {
        console.log('Client disconnected!')
    })
})

ในส่วนของ Server-Side เราจะ Listen ที่ Port 4000 โดยเราจะใช้ตัวแปร server ที่เก็บฟังก์ชั่น http.createServer(app)  ทำการ listen แทนที่จะใช้ app ซึ่งเก็บฟังก์ชั่น express() แทน แต่การ routing ไปยังหน้าต่างๆ เราก็ยังใช้ app.get, app.post จาก express เหมือนเดิม

ใน path /chat ผมจะให้ express ทำการ Serve Chat Page ซึ่งมี Script Socket.io ที่จะทำงานเป็น Client-Side ให้กับ Client

เราจะ listen sockets ที่ Client จะส่งมา โดยการใช้ io.on('connection') ซึ่งจะถูกเรียกใช้ เมื่อมี Socket.io จากฝั่ง Client เชื่อมต่อเข้ามา ขณะที่เชื่อมต่ออยู่ หากมีการ emit "chat_message" เข้ามา เราจะ boardcast กลับไปหา client ทุกคน ด้วยฟังก์ชั่น socket.emit('chat_message')

Client-Side (chat page)

<html>
    <head>
        <script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
    </head>
    <body>
        <ul id="chat_display">
        </ul>
        <input type='text' id="chat_input">
        <button onclick='send_message'>Send</button>
        <script>
            const socket = io();

            function send_message() {
                chat_input = document.getElementById("chat_input")
                if(chat_input != '') {
                    socket.emit('chat_message', {
                        msg:chat_input.value
                    })
                    chat_input.value = ''
                }
            }

            socket.on('chat_message', (msg) => {
                chat_display = document.getElementById("chat_display")
                msg_node = document.createElement("li")
                msg_node.innerHTML = `Message: ${msg}`
                chat_display.appendChild(msg_node)
                document.getElementById("chat_display").lastElementChild.scrollIntoView({ behavior: 'smooth' });
            })
        </script>
    </body>
</html>

ในฝั่ง Client เราก็เตรียมฟังก์ชั่น send_message ที่จะใช้สำหรับ emit ข้อมูลไปหา server ไว้ โดยเมื่อมีการเรียกใช้ฟังก์ชั่น จะไปนำข้อมูล text ที่อยู่ใน #chat_input เข้ามาและ emit ซึ่ง send_message จะถูกเรียกใช้เมื่อ click ปุ่ม "Send"

จากนั้นเราจะมี ฟังก์ชั่น socket.on('chat_message') ไว้รอรับ ข้อมูลที่ Server จะ Boardcast ลงมา และนำไปสร้างเป็น li ใน ul#chat_display เมื่อ Server ได้ emit ฟังก์ชั่นดังกล่าวก็จะทำงาน และเพิ่มข้อมูลลงไป

อ้างอิง:

socket.io

Profile Picture.
  • Name (Pen name): Sunny Jirakit (Sunny420x)
  • Study: Bachelor Degree of Computer Science from Chiang Mai Rajabhat University
  • Personality: Architect (INTJ-T)
  • Experience: JavaScript,  Angular.js, React.js, Next.js  Express.js, Unity C#, Socket.io