โ๏ธ ํ๋ก์ ํธ ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ์ ์ํด zoom ํด๋ก ์ฝ๋ฉ ์ค์ต(๋ฐ๋๋ผ JS, websocket)์ ํด๋ณด๋ฉด์ ๊ธฐ๋กํ ๋ด์ฉ์ด๋ค. (1)
npm init -y
npm i nodemon -D
npm i @babel/core @babel/cli @babel/node -D
npm i @babel/preset-env -D
npm i express
npm i pug
๐ nodemon
ํ๋ก์ ํธ๋ฅผ ์ดํด๋ณด๊ณ ๋ณ๊ฒฝ ์ฌํญ์ด ์์ ์ ์๋ฒ๋ฅผ ์ฌ์์ํด์ฃผ๋ ํ๋ก๊ทธ๋จ
// nodemon.json
{
"ignore": ["src/public/*"],
"exec": "babel-node src/server.js"
}
๐ server.js
BackEnd์์ ๊ตฌ๋๋จ
import express, { application } from 'express'; // express๋ฅผ import
const app = express(); // express ์ดํ๋ฆฌ์ผ์ด์
์ ๊ตฌ์ฑ
app.set('view engine', 'pug'); // ์ฌ๊ธฐ์ view engine์ Pug๋ก ์ค์ ,
app.set('views', __dirname + '/public/views'); // views ๋๋ ํ ๋ฆฌ๊ฐ ์ค์
app.use('/public', express.static(__dirname + '/public')); // 1)
app.get('/', (req, res) => res.render('home'));
app.get('/*', (req, res) => res.redirect('/')); // ์ ์ ๊ฐ ์ด๋ url์ ์
๋ ฅํด๋ ํ์ผ๋ก
const handleListen = () => console.log('hello');
app.listen(3000, handleListen);
const server = http.createServer(app); // http ์๋ฒ
const wss = new WebSocket.Server({server}) // WebSocket ์๋ฒ
public
: FrontEnd์์ ๊ตฌ๋๋๋ ์ฝ๋ (public > js > FrontEnd์์ ๊ตฌ๋)npm i ws
โ ws ์ค์นํ๊ธฐconst handleConnection = (socket) => {
console.log(socket); // *)
};
wss.on('connection', handleConnection);
// *) ์ด์ํ์์๋ ์๋ฌด ์ฐ๊ฒฐ์ด ์์ผ๋ฏ๋ก ์๋ฌด์ผ์ด ์ผ์ด๋์ง ์์. backend์ ์ฐ๊ฒฐ ํ์
1) on method์์๋ envent๊ฐ ๋ฐ๋ํ๋ ๊ฒ์ ๊ธฐ๋ค๋ฆฐ๋ค. (์ ๊ฒฝ์ฐ connection ์ด๋ฒคํธ)
2) ๊ทธ๋ฆฌ๊ณ function ์ ๋ฐ๋๋ฐ connection์ด ์ด๋ฃจ์ด์ง๋ฉด ์๋ํ๋ค.
3) ๋ on method๋ backend์ ์ฐ๊ฒฐ๋ ์ฌ๋์ ์ ๋ณด๋ฅผ ์ ๊ณตํด์ค๋ค. (๊ทธ๊ฒ socket์์ ์จ๋ค.)
on
frontend ์์ backend๋ก ์ฐ๊ฒฐํ๊ธฐ
const ์์ผ = new WebSocket(url, protocols)
app.js ์์ ์ฐ๊ฒฐํด๋ณด๊ธฐ
โ๏ธ webSocket์ ๋ธ๋ผ์ฐ์ ์ ์๋ฒ์ฌ์ด์ ์ฐ๊ฒฐ์ด๋ค! ๐
const socket = new WebSocket(`ws://${window.location.host}`);
server.js์ app.js์ socket
1) ์ฐ๊ฒฐ๋ ๋ธ๋ผ์ฐ์ ๋ฅผ ๋ปํ๋ค.
// server.js
// ์ด socket์ด frontend์ real-time ์ผ๋ก ์ํตํ ์ ์๋ค.
const handleConnection = (socket) => {
console.log(socket);
};
2) ์๋ฒ๋ก์ ์ฐ๊ฒฐ์ ๋ปํ๋ค.
// app.js
// ๋ง์ฐฌ๊ฐ์ง๋ก frontend์์ backend๋ก ๋ฉ์ธ์ง๋ฅผ ๋ณด๋ผ ์ ์๋ค.
const socket = new WebSocket(`ws://${window.location.host}`);
1) ์ฐ๊ฒฐ์ ํด์ socket์ ์๊ธฐ
2) ๋ธ๋ผ์ฐ์ ์ ๋ฉ์ธ์ง ๋ณด๋ด๋ณด๊ธฐ
โ socket์ ์๋ ๋ฉ์๋๋ฅผ ์ฌ์ฉํด๋ณด๊ธฐ! (wss์๋ฒ์ ์๋ ๋ฉ์๋๊ฐ ์๋)
// server.js
wss.on('connection', (socket) => { // connection์ด ์๊ฒผ์ ๋ socket์ผ๋ก ์ฆ์ ๋ฉ์ธ์ง('hi!!!')๋ฅผ ๋ณด๋ด๊ธฐ
console.log('Connected to Browser ๐');
socket.send('hi!!!');
});
3) ํ๋ก ํธ์์ ๋ฉ์ธ์ง ๋ฐ๊ธฐ & socket์ ์ด๋ฒคํธ๋ฅผ ์ถ๊ฐํด๋ณด๊ธฐ
// app.js
const socket = new WebSocket(`ws://${window.location.host}`<);
socket.addEventListener('open', () => { // connection์ด open๋๋ฉด ์๋ ์ฝ์ ์ถ๋ ฅ
console.log('Connected to Server ๐ซ');
});
socket.addEventListener('message', (message) => { // ๋ฉ์ธ์ง๋ฅผ ๋ฐ์ ๋๋ง๋ค ๋ด์ฉ์ ์ถ๋ ฅํ๋ message
console.log('Just got this: ', message, 'from the server');
// message.data -> hi!!!
});
socket.addEventListener('close', () => { // ์๋ฒ๊ฐ ์คํ๋ผ์ธ์ด ๋ ๋ ์๋ ์ฝ์ ์ถ๋ ฅ
console.log('Disconnect from Server ๐ฅ');
});
4) ํ๋ก ํธ์์ ๋ฉ์ธ์ง ๋ณด๋ด๊ธฐ
// app.js
setTimeout(() => {
socket.send('๋ธ๋ผ์ฐ์ ์์ ๋ฉ์ธ์ง ๋ณด๋ด๊ธฐ!');
}, 5000);
pug๋ก UI ์์ฑ
// pug ๋ก UI ์์ฑ
body
header
h1 seul
main
h2 Welcome to seul
ul
form
input(type="text", placeholder="๋ฉ์ธ์ง", required)
button Send
script(src="/public/js/app.js")
// app.js
const messageList = document.querySelector('ul');
const messageForm = document.querySelector('form');
function handleSubmit(e) {
e.preventDefault();
const input = messageForm.querySelector('input');
socket.send(input.value); // ๋ฐฑ์๋๋ก ๋ฉ์ธ์ง๋ฅผ ๋ณด๋
input.value = '';
}
messageForm.addEventListener('submit', handleSubmit);
const sockets = [];
wss.on('connection', (socket) => {
sockets.push(socket);
...
// ์ด๋ฐ ํํ๋ก ๋ง๋ค์ด์ฃผ๊ธฐ์ํด!!
{
type: 'message';
payload: 'ํฌ๋ก';
}
{
type: 'nickname';
payload: 'seul';
}
function handleNickSubmit(e) {
e.preventDefault();
const input = nickForm.querySelector('input');
socket.send({
type: 'nickname',
payload: input.value,
});
input.value = '';
}
back-end๋ก string ๋ณด๋ด์ฃผ๊ธฐ
const messageList = document.querySelector('ul');
const nickForm = document.querySelector('#nick');
const messageForm = document.querySelector('#message');
const socket = new WebSocket(`ws://${window.location.host}`);
function makeMessage(type, payload) {
const msg = { type, payload };
return JSON.stringify(msg);
}
...
function handleSubmit(e) {
e.preventDefault();
const input = messageForm.querySelector('input');
socket.send(makeMessage('์๋ก์ด ๋ฉ์ธ์ง', input.value));
input.value = '';
}
function handleNickSubmit(e) {
e.preventDefault();
const input = nickForm.querySelector('input');
socket.send(makeMessage('๋๋ค์', input.value));
input.value = '';
}
messageForm.addEventListener('submit', handleSubmit);
nickForm.addEventListener('submit', handleNickSubmit);
ํ์ ๋ถ๊ธฐ
socket.on('message', (message) => {
const parsed = JSON.parse(message.toString());
if (parsed.type === '์๋ก์ด ๋ฉ์ธ์ง') {
sockets.forEach((aSocket) => aSocket.send(parsed.payload));
}
});
swicth ๋ฌธ ํ์ฉํ์ฌ ๋ถ๊ธฐ ๋ฆฌํฉํ ๋ง
wss.on('connection', (socket) => {
sockets.push(socket);
console.log('ํด๋ผ์ด์ธํธ / ๋ธ๋ผ์ฐ์ ์ ์ฐ๊ฒฐ ๐');
socket.send('hi!!!');
socket.on('close', () =>
console.log('ํด๋ผ์ด์ธํธ / ๋ธ๋ผ์ฐ์ ๋ก๋ถํฐ ์ฐ๊ฒฐ์ด ๋๊น๐ฅ')
);
socket.on('message', (msg) => {
const message = JSON.parse(msg.toString());
switch (message.type) {
case '์๋ก์ด ๋ฉ์ธ์ง': {
sockets.forEach((aSocket) => aSocket.send(message.payload));
}
case '๋๋ค์': {
console.log(message.payload);
}
}
});
});
๋ง์ฝ type์ด ๋๋ค์์ธ ๋ฉ์ธ์ง๋ฅผ ๋ฐ์ผ๋ฉด ๋๋ค์์ socket์ ๋ฃ์ด์ค๋ค. (๋๋ค์์ด๋ ์ด๋ฉ์ผ์ด๋ ์ํ๋ ์ ๋ณด๋ฅผ ๋ฃ์ด์ค ์ ์๋ค.)
wss.on('connection', (socket) => {
sockets.push(socket);
socket['๋๋ค์'] = '์์'
console.log('ํด๋ผ์ด์ธํธ / ๋ธ๋ผ์ฐ์ ์ ์ฐ๊ฒฐ ๐');
socket.send('hi!!!');
socket.on('close', () =>
console.log('ํด๋ผ์ด์ธํธ / ๋ธ๋ผ์ฐ์ ๋ก๋ถํฐ ์ฐ๊ฒฐ์ด ๋๊น๐ฅ')
);
socket.on('message', (msg) => {
const message = JSON.parse(msg.toString());
switch (message.type) {
case '์๋ก์ด ๋ฉ์ธ์ง': {
sockets.forEach((aSocket) => aSocket.send(message.payload));
}
break; // ๋ถ์ด์ง ์์ผ๋ฉด ์ฌ๋ฌ๋ฒ ๋ฉ์ธ์ง๋ฅผ ์
๋ ฅํ ๋๋ง๋ค ๋๋ค์์ด ๋ฐ๋
case '๋๋ค์': {
console.log(message.payload);
socket['๋๋ค์'] = message.payload; // ๋ฐ์ ๋๋ค์์ ๋๋ค์์์ผ์ ๋ฃ์ด์ฃผ๊ณ ์๋์ค
}
break;
}
});
});
๐ ํธ์์ฑ ๊ฐ์ ํ๊ธฐ (๋ฌธ์ ์ )
1) ๋๋ฅผ ์ ์ธํ ๋ค๋ฅธ ์ฌ๋ ๋ชจ๋์๊ฒ๋ง ๋ฉ์ธ์ง๋ฅผ ์ ์กํ๊ธฐ
์ง๊ธ์ ๋ฉ์ธ์ง๋ฅผ ๋ณด๋ผ ๋ ๋ฉ์ธ์ง๊ฐ ์๋ฒ๋ก ๊ฐ๊ณ , ๋ฉ์ธ์ง ํ์
์ ๋ฐ๋ผ์ ์์ ๊ณผ ๋ค๋ฅธ ๋ธ๋ผ์ฐ์ ์ ์ ์กํ๊ณ ์๋ค. ๋ฐ๋ผ์ ๋ง์ฝ brave๊ฐ ๋ฉ์ธ์ง๋ฅผ ๋ณด๋ด๋ฉด brave์๋ ๋ฉ์ธ์ง๋ฅผ ๋ณด๋ด์ฃผ๊ณ ์๋ค. โ ๊ฐ์ ๋ฉ์ธ์ง๋ฅผ ๋๋ ค์ฃผ๋ ์ค
2) ์ฌ๋ฌ ์ข
๋ฅ์ ๋ฉ์ธ์ง ์ปจํธ๋กค
๋ธ๋ผ์ฐ์ ๊ฐ ๋ฐฑ์๋์๊ฒ ์ฌ๋ฌ ์ข
๋ฅ์ ๋ฉ์ธ์ง๋ฅผ ์ฃผ๋ ๊ฒ์ฒ๋ผ (๋๋ค์, ์๋ก์ด๋ฉ์ธ์ง) ๋ฐฑ์๋๋ ํ๋ก ํธ์๊ฒ ์ฌ๋ฌ ์ข
๋ฅ์ ๋ฉ์ธ์ง๋ฅผ ์ค ์ ์๋ค. (์ฑํ
๋ฐฉ ์
์ฅํ ์ฌ๋, ์ฑํ
๋ฐฉ ๋๊ฐ์ฌ๋ ๋ฑ)
โ ๋ค์๋งํด์, (ํ์ฌ ๋ฐฉ์์ ๋ฐ๋์ฒ๋ผ) ๋ฐฑ์์ stringify๋ฅผ ํด์ฃผ๊ณ , ๋๊ธด ๋ฐ์ดํฐ๋ฅผ ํ๋ก ํธ์์ ๋ค์ parse๋ฅผ ํด์ค์ผํ ์๋ ์๋ค๋ ๊ฒ๐ง
โ๏ธ ์ง๊ธ์ ๋ชจ๋ ๊ฒ๋ค์ด socket message๋ก ๋ค์ด๊ฐ์ผ ๋ฉ์ธ์ง ํ์
์ ํ์ธํ ์ ์๋๋ฐ ์์ผ์์ด์ค ํ๋ ์์ํฌ๋ฅผ ์ฐ๋ฉด socket.on(โnicknameโ, fn)
๊ณผ ๊ฐ์ด ์ฌ์ฉํ ์ ์๋ค!!! ๐
์ด๋ฌํ ์ ๋ค์ Socket.IO ๋ฅผ ํตํด์ ์ฝ๊ฒ ํด๊ฒฐํ ์ ์๋ค๊ณ ํ๋ค.
wss์๋ ์ ์ผ ๊ธฐ์ด์ ์ธ ๊ฒ๋ค์ด ์๋ค. ์ค๋ก์ง web socket specification์ ๋ง์ถฐ protocol์ ์คํ์ํฌ ๋ฟ์ด๋ค. ๋ถ์์ ์ธ ๊ธฐ๋ฅ๋ ์๋ค๊ณ ํ๋ค.
ํ๋ก์ ํธ ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ์ ์์ Websocket๊ณผ Socket.IO ๊ฐ๋ ์๊ณ ์ตํ๊ธฐ. ์ค์ต ํ๋ก์ ํธ !
1. JavaScript + Websocket ๐ WebSocket ์ผ๋ก ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ ํด๋ณด๊ธฐ
2. JavaScript + Socket.IO ๐ Socket.IO๋ก ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ ํด๋ณด๊ธฐ
3. React + Socket.IO ๐ Socket.IO๋ก ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ ํด๋ณด๊ธฐ
โจ with-dog ํ๋ก์ ํธ ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ ๐ ์ฑํ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ