โ๏ธ ํ๋ก์ ํธ ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ์ ์ํด zoom ํด๋ก ์ฝ๋ฉ ์ค์ต(๋ฐ๋๋ผ JS, socket.io)์ ํด๋ณด๋ฉด์ ๊ธฐ๋กํ ๋ด์ฉ์ด๋ค.(2)
์น ํ์ด์ง์ ํ๊ณ์์ ๋ฒ์ด๋ ์ค์๊ฐ์ผ๋ก ์ํธ์์ฉํ๋ ์น ์๋น์ค๋ฅผ ๋ง๋๋ ํ์ค ๊ธฐ์ ์ธ WebSocket ๊ทธ๋ฆฌ๊ณ ๋ค์ํ ๋ฐฉ์์ ์ค์๊ฐ ์น ๊ธฐ์ ์ ์์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋ Socket.io์ ๋ํด์ ์์๋ณด์! ๐ค
๊ธฐ์กด์ HTTP ํ๋กํ ์ฝ์ ์๋ฒ์ ํด๋ผ์ด์ธํธ ์ฌ์ด์ ์ฐ๊ฒฐ์ด ์ ์ง๋์ง ์๋๋ค. (connectionless) ๋ฐ๋ผ์ ์ํธ์์ฉ(์ค์๊ฐ ํต์ )ํ๋ ์น ์๋น์ค๋ฅผ ์ํด์๋ ์จ๊ฒจ์ง ํ๋ ์(Hidden Frame)์ ์ด์ฉํ ๋ฐฉ๋ฒ์ด๋ Long Polling, Stream ๋ฑ ๋ค์ํ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๋ฉฐ ๋ณต์กํ๊ณ ์ด๋ ค์ด ์ฝ๋๋ก ๊ตฌํํ๋ค.
๋ณด๋ค ์ฝ๊ฒ ์ํธ์์ฉํ๋ ์น ํ์ด์ง๋ฅผ ๋ง๋ค๋ ค๋ฉด ๋ธ๋ผ์ฐ์ ์ ์น ์๋ฒ ์ฌ์ด์ ๋์ฑ ์์ ๋ก์ด ์๋ฐฉํฅ ๋ฉ์์ง ์ก์์ ์ด ํ์ํ๋ค. ๊ทธ๋์ HTML5 ํ์ค ๊ธฐ์ ๋ก Websocket API๊ฐ ๋ฑ์ฅํ๊ฒ ๋์๋ค.
WebSocket์ ์์ผ์ ์ด์ฉํ์ฌ ์๋ฒ์ ํด๋ผ์ด์ธํธ ์ฌ์ด์์ ์์ ๋กญ๊ฒ ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ๋ ์๋ฐฉํฅ ํต์ ์ ๊ฐ๋ฅํ๊ฒ ํ๋ฏ๋ก ๊ธฐ์กด์ ์์ฒญ-์๋ต ๊ด๊ณ ๋ฐฉ์๋ณด๋ค ๋ ์ฝ๊ฒ ๋ฐ์ดํฐ ๊ตํ์ด ๊ฐ๋ฅํ๊ฒ ๋์๋ค.
Socket.IO๋ node.js ๊ธฐ๋ฐ์ผ๋ก ๋ง๋ค์ด์ง ๊ธฐ์ ๋ก, ๊ฑฐ์ ๋ชจ๋ ์น ๋ธ๋ผ์ฐ์ ์ ๋ชจ๋ฐ์ผ ์ฅ์น๋ฅผ ์ง์ํ๋ ์ค์๊ฐ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ง์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค.
์ฌ๋ฌ ์ ํ์ง ์ค์์ websocket์ ์ด์ฉํด์ ์ค์๊ฐ & ์๋ฐฉํฅ & event๊ธฐ๋ฐ ํต์ ์ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค. (websocket์ ์คํํ๋๊ฒ ์๋๋ค.)
์ด๋ค ๋ธ๋ผ์ฐ์ ๋ ํธ๋ํฐ์ด websocket์ ์ง์ํ์ง ์์ ๋(websocket์ฐ๊ฒฐ์ ํ ์ ์์ ๊ฒฝ์ฐ) socket.IO๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ(HTTP long polling ๋ฑ)์ ์ด์ฉํด์ ๊ณ์ ์๋์ ํ๋ค.
โ ์ฆ socket.IO๋ websocket์ ๋ถ๊ฐ๊ธฐ๋ฅ์ด ์๋๋ค.
์์ผ ์ฐ๊ฒฐ ์คํจ ์ fallback์ ํตํด ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก ์์์ ํด๋น ํด๋ผ์ด์ธํธ์ ์ฐ๊ฒฐ์ ์๋ํ๋ค.
๋ง์ฝ wifi์ฐ๊ฒฐ์ด ์ ์๋์ ๋๊ฒจ๋ ์ฌ์ฐ๊ฒฐ์ ์๋ํ๋ค. (webSockets์ ๊ฒฝ์ฐ ์ด ์ฌ์ฐ๊ฒฐ ๊ธฐ๋ฅ์ ์ง์ ๋ง๋ค์ด์ค์ผ๋ง ํ๋ค.)
๋ชจ๋ ํ๋ซํผ, ๋ธ๋ผ์ฐ์ , ๋๋ฐ์ด์ค์์ ์ด์ฉ ๊ฐ๋ฅํ๋ค.
๐ ์ด๋ค ์ํฉ์์ ์ด๋ค๊ฑธ ์ฌ์ฉํด์ผ ํ ๊น?
npm i socket.io
// server.js
const io = SocketIO(httpServer);
// app.js
const socket = io();
(์ฌ๊ธฐ์๋ WebSocket์ด ์๋๋ผ Socket์ผ๋ก ๋ณด์)
1) ํน์ ํ event๋ฅผ emitํด์ค ์ ์๋ค.
์ด๋ค์ด๋ฆ์ด๋ ์๊ด X (๊ผญ message ์ด๋ฒคํธ๊ฐ ์๋๋ผ ์ํ๋ ์ด๋ฒคํธ๋ฉด ๋๋ค !)
2) ์ค๋ธ์ ํธ๋ฅผ ์ ์กํ ์ ์๋ค. ์ด์ ์ฒ๋ผ string๋ง ์ ์กํ ํ์ X
โ socket IO๋ obj๋ฅผ string์ผ๋ก ์์์ ๋ฐ๊ฟ์ฃผ๊ณ , ๋ค์ ์์์ JS object๋ก ๋ง๋ค์ด์ค๋ค.๐
// app.js
const socket = io();
const welcome = document.getElementById('welcome');
const form = welcome.querySelector('form');
function handleRoomSubmit(e) {
e.preventDefault();
const input = form.querySelector('input');
socket.emit('enter_room', { payload: input.value }); // enter_room์ด๋ผ๋ event๋ฅผ emit
input.value = '';
}
form.addEventListener('submit', handleRoomSubmit);
// server.js
io.on('connection', (socket) => {
console.log(socket);
socket.on('enter_room', (msg) => console.log(msg)); // ์ด์ ์ฒ๋ผ 'message' ํ ํ์ ์์ด ์ํ๋ ์ด๋ฒคํธ๋ฅผ ๋ฃ์
});
// ๐ socket.on๊ณผ app.js์ socket.emit์ 'enter_room' ์ด๋ฆ ๋ง์ถฐ์ฃผ๊ธฐ !!
// ๐ msg๋ app.js์ ๋๋ฒ์งธ์ธ์๊ฐ ๋ณด๋ธ JSON ์ค๋ธ์ ํธ์ด๋ค.
3) socket.emit์ ์ธ๋ฒ์งธ argument
// app.js
function handleRoomSubmit(e) {
e.preventDefault();
const input = form.querySelector('input');
socket.emit('enter_room', { payload: input.value }, () => {
console.log('server id done!');
});
input.value = '';
}
// server.js
io.on('connection', (socket) => {
// console.log(socket);
socket.on('enter_room', (msg, done) => {
console.log(msg);
setTimeout(() => {
done();
}, 5000);
});
});
โ ๊ถ๊ธํ๋ ๊ฒ
์ธ์์ ์ด๋ค๊ฑธ ๋ฃ์ด๋ ๋ณด๋ผ ์ ์๋๋ฐ ์ธ๋ฒ์งธ ์ธ์๊ฐ ์ฝ๋ฐฑํจ์๋ฅผ ๊ผญ ๋ฐ๋๊ฒ ์๋๊ฑด๊ฐ?
โ๏ธ ๋ต: ๋ง์ง๋ง ์ธ์์ ํจ์๋ฅผ ๋ฃ์ผ๋ฉด ๋๋ค. ๐ ๊ทธ์ธ์๋ ๋ฌด์ ํ ์ผ๋ก ์ธ์๋ฅผ ๋๊ฒจ์ฃผ๊ณ ๋ค ๋ฐ์์ฌ ์ ์๋ค.
โ ์ด๋์์ ์คํ์ํค๋ ๊ฑฐ์ผ ๐ง?
// server.js
io.on('connection', (socket) => {
// console.log(socket);
socket.on('enter_room', (msg, done) => {
console.log(msg);
setTimeout(() => {
done('์๋
ํ๋ก ํธ์๋ ?'); // 1)
}, 5000);
});
});
// app.js
function handleRoomSubmit(e) {
e.preventDefault();
const input = form.querySelector('input');
socket.emit('enter_room', { payload: input.value }, (msg) => {
console.log('๋ฐฑ์๋์์ ๋ณด๋ธ ๋ฉ์ธ์ง: ', msg); // 2)
});
input.value = '';
}
1) done() ํจ์๋ฅผ ์คํ์ํค๋ฉด back-end์์ ์ด ์ฝ๋๋ฅผ ์คํ์ํค์ง ์๋๋ค. ๋ณด์ ๋ฌธ์ ๊ฐ ์๊ธฐ๊ธฐ ๋๋ฌธ์ด๋ค. (โ๏ธ์ ๋ขฐํ์ง ๋ชปํ๋ ์ฝ๋๋ฅผ back-end์์ ์คํ์ํค๋ฉด ์๋๋ค.)
2) front-end์์ ์คํ ๋ฒํผ์ ๋๋ฌ์ฃผ๋ ๊ฑฐ๋ผ๊ณ ์ดํดํ๊ธฐ!
โ ์ฆ, Front-end์์ ์คํ๋ ์ฝ๋๋ back-end๊ฐ ์คํ์ ์ํจ๊ฒ์ด๋ค. ๐ค
โ๏ธ ํท๊ฐ๋ฆฌ๋ ๋๋์ด๋ผ์ ์ง์ ์๊ฐํด๋ณด์๋ฉด, ํจ์ํธ์ถ์ ๋ฐฑ์๋, ์คํ์ ํ๋ก ํธ !!!!
ํ๋ก ํธ์๋์์ ์คํ์ฝ๋๋ฅผ ๋ง๋ค๊ณ , ๋ฐฑ์๋๊ฐ ๊ทธ ์ฝ๋๋ฅผ ํธ์ถํ๋๋ฐ ์คํ์์ฒด๋ ๋ฐฑ์์ ๋๋๊ฒ ์๋๋ผ ๋ฐฑ์ด ํธ์ถํ ํ๋ก ํธ๋ก ๋์ด์์ ํ๋ก ํธ์์ ์คํ์ด ๋๋ค๊ณ ์ดํดํ๋ค. ์ด๋ ๋ฐฑ์๋์์ ์ธ์๋ฅผ ๋ฃ์ด์ ํ๋ก ํธ๋ก ๋ณด๋ด๋ ๊ฒ๋ ๊ฐ๋ฅ!
socket.join('') // room์ด๋ฆ๋ง ๋ฃ์ด์ฃผ๋ฉด ๋๋ค.
// ๊ณต์๋ฌธ์
io.on("connection", (socket) => {
socket.join("room 237");
console.log(socket.rooms); // Set { <socket.id>, "room 237" }
socket.join(["room 237", "room 238"]); // ๋์์ ์ฌ๋ฌ๋ฐฉ์ ์ฐธ๊ฐ๋ ๊ฐ๋ฅ!
io.to("room 237").emit("a new user has joined the room"); // broadcast to everyone in the room
});
io.on("connection", (socket) => {
socket.leave("room 237");
io.to("room 237").emit(`user ${socket.id} has left the room`);
});
io.on("connection", (socket) => {
// to one room
// others ๋ผ๋๋ฐฉ์ ์ด๋ฒคํธ๋ฅผ ๋ณด๋ผ ์ ์๋ค.
socket.to("others").emit("an event", { some: "data" });
// to multiple rooms
socket.to("room1").to("room2").emit("hello");
// or with an array
socket.to(["room1", "room2"]).emit("hello");
// a private message to another socket
// ๋ค๋ฅธ socket์ ID๋ฅผ ์๋ค๋ฉด ํ๋ผ์ด๋น ๋ฉ์ธ์ง๋ฅผ ๋ณด๋ผ ์ ์๋ค!
socket.to(/* another socket id */).emit("hey");
// WARNING: `socket.to(socket.id).emit()` will NOT work, as it will send to everyone in the room
// named `socket.id` but the sender. Please use the classic `socket.emit()` instead.
});
// ๊ณต์๋ฌธ์
io.on("connection", (socket) => {
console.log(socket.rooms); // Set { <socket.id> } // 1)
socket.join("room1");
console.log(socket.rooms); // Set { <socket.id>, "room1" }
});
socket.onAny((event, ...args) => {
console.log(`got ${event}`);
});
io.on('connection', (socket) => {
socket.onAny((e) => {
console.log(`์์ผ์ด๋ฒคํธ: ${e}`);
});
socket.on('enter_room', (roomName, done) => {
console.log('socket.rooms(1): ', socket.rooms); // ์์ผ์ด ์ด๋ค ๋ฐฉ์ ์๋์ง ์๊ธฐ์ํด ์ถ๋ ฅ
socket.join(roomName); // ๋ฐฉ์ ์ฐธ๊ฐ๋ฅผ ํ๊ณ
console.log('socket.rooms(2): ', socket.rooms); // ์์ผ์ด ์ด๋ค ๋ฐฉ์ ์๋์ง ์๊ธฐ์ํด ์ถ๋ ฅ
setTimeout(() => {
done('์๋
ํ๋ก ํธ์๋ ?');
}, 5000);
});
});
io.sockets.emit
์ ํ๋ฉด ๋ชจ๋์๊ฒ ๋ฉ์ธ์ง๋ฅผ ๋ณด๋ผ ์ ์๋ค.io.sockets.emit("hi", "everyone");
// is equivalent to
io.of("/").emit("hi", "everyone");
// make all Socket instances join the "room1" room
// ๋ชจ๋ ์์ผ์ด ์ด room์ ๊ฐ์ ๋ก ๋ค์ด๊ฐ๊ฒ ํจ
io.socketsJoin("room1");
// make all Socket instances in the "room1" room join the "room2" and "room3" rooms
// room1์ ์๋ ๋ชจ๋ socket์ room2์ room3์ ๋ค์ด๊ฐ๊ฒ ํจ
io.in("room1").socketsJoin(["room2", "room3"]);
// this also works with a single socket ID
io.in(theSocketId).socketsJoin("room1");
ex.) socket์ด ์ฐ๊ฒฐ๋์์ ๋ ๋ชจ๋ socket์ด ๊ณต์ง๋ฐฉ์ ์ ์ฅํ๊ฒ ๋๋ค.
io.on('connection', (socket) => {
io.socketsJoin('๊ณต์ง๋ฐฉ');
...
// server.js
io.on('connection', (socket) => {
socket.onAny((e) => {
console.log(`์์ผ์ด๋ฒคํธ: ${e}`);
});
socket.on('enter_room', (roomName, done) => {
socket.join(roomName);
done();
});
});
// server.js
io.on('connection', (socket) => {
socket.onAny((e) => {
console.log(`์์ผ์ด๋ฒคํธ: ${e}`);
});
socket.on('enter_room', (roomName, done) => {
socket.join(roomName); // 1. ๋ฐฉ์ ์ฐธ๊ฐํ๋ฉด
done(); // 2. ํจ์๋ฅผ ํธ์ถํ๊ณ
socket.to(roomName).emit('์ฐ์ปด'); // 4. '์ฐ์ปด' event๋ฅผ rommName์ ์๋ ๋ชจ๋ ์ฌ๋๋ค์๊ฒ emit ํจ
});
});
// ๐ ์์ผ์ด ๋ค๋ฅด๋ฏ๋ก ์ ๋
ธ๋์์ ์ฝ๋๋ ์ฌํ๋ฆฌ์์ ํ๋ฒ, ํฌ๋กฌ์์ ํ๋ฒ ๋ ์คํ๋๋ค. ๋๋ฒ ์คํ
// add.js
function addMessage(msg) {
const ul = room.querySelector('ul');
const li = document.createElement('li');
li.innerText = msg;
ul.appendChild(li);
}
// 3. done()์ ํ๋ก ํธ์๋์ ์๋ showRoom()์ ์คํ
function showRoom() {
console.log('๋ฐฑ์๋์์ ํธ์ถ');
welcome.hidden = true;
room.hidden = false;
const h3 = room.querySelector('h3');
h3.innerText = `Room ${roomName}`;
}
function handleRoomSubmit(e) {
e.preventDefault();
const input = form.querySelector('input');
socket.emit('enter_room', input.value, showRoom);
roomName = input.value;
input.value = '';
}
form.addEventListener('submit', handleRoomSubmit);
socket.on('์ฐ์ปด', () => {
addMessage('๋๊ตฐ๊ฐ ๋ค์ด์์ต๋๋ค!');
});
io.on("connection", (socket) => {
socket.on("disconnecting", (reason) => {
console.log(socket.rooms); // Set { ... } //<- ์ฌ๊ธฐ์ Set์ ๋ฐ๋ณต๊ฐ๋ฅํ๋ฏ๋ก forEach๋ฌธ ์์ฑ ๊ฐ๋ฅ!
});
});
socket.on('disconnecting', () => {
socket.rooms.forEach(room => socket.to(room).emit('๋ฐ์ด'))
});
io.on('connection', (socket) => {
socket.onAny((e) => {
console.log(`์์ผ์ด๋ฒคํธ: ${e}`);
});
socket.on('enter_room', (roomName, done) => {
socket.join(roomName);
done();
socket.to(roomName).emit('์ฐ์ปด');
socket.on('disconnecting', () => {
socket.rooms.forEach((room) => socket.to(room).emit('๋ฐ์ด'));
});
});
});
socket.on('๋ฐ์ด', () => {
addMessage('๋๊ตฐ๊ฐ ๋ ๋ฌ์ต๋๋ค ใ
ใ
...');
});
// server.js
io.on('connection', (socket) => {
socket.onAny((e) => {
console.log(`์์ผ์ด๋ฒคํธ: ${e}`);
});
socket.on('enter_room', (roomName, done) => {
socket.join(roomName); // 1. ๋ฐฉ์ ์ฐธ๊ฐํ๋ฉด
done(); // 2. ํจ์๋ฅผ ํธ์ถํ๊ณ
socket.to(roomName).emit('์ฐ์ปด'); // 4. '์ฐ์ปด' event๋ฅผ rommName์ ์๋ ๋ชจ๋ ์ฌ๋๋ค์๊ฒ emit ํจ
socket.on('disconnecting', () => {
socket.rooms.forEach((room) => socket.to(room).emit('๋ฐ์ด'));
});
socket.on('new_message', (msg, room, done) => {
socket.to(room).emit('new_message', msg); // new_message ์ด๋ฆ์ด ๊ฐ์๋ ์๊ด ์๋ค. / ์ด ์์
์ด ๋๋ ๋ค ์๋ done ํจ์ ํธ์ถ
done();
});
});
});
// app.js
function addMessage(msg) {
const ul = room.querySelector('ul');
const li = document.createElement('li');
li.innerText = msg;
ul.appendChild(li);
}
...
// socket.on('new_message', (msg)=>{addMessage(msg)})์ ๊ฐ์
socket.on('new_message', addMessage);
// ํจ์ ๋ก์ง ๋ณ๊ฒฝ
// app.js
function handleNicknameSubmit(e) {
e.preventDefault();
const input = room.querySelector('#name input');
socket.emit('nickname', input.value);
}
...
const msgForm = room.querySelector('#msg');
const nameForm = room.querySelector('#name');
msgForm.addEventListener('submit', handleMessageSubmit);
nameForm.addEventListener('submit', handleNicknameSubmit);
...
// server.js
socket.on('nickname', (nickname) => (socket['nickname'] = nickname));
io.on('connection', (socket) => {
socket['nickname'] = '์ต๋ช
';
socket.onAny((e) => {
console.log(`์์ผ์ด๋ฒคํธ: ${e}`);
});
socket.on('enter_room', (roomName, done) => {
socket.join(roomName);
done();
socket.to(roomName).emit('์ฐ์ปด', socket.nickname);
});
socket.on('disconnecting', () => {
socket.rooms.forEach((room) =>
socket.to(room).emit('๋ฐ์ด', socket.nickname)
);
});
socket.on('new_message', (msg, room, done) => {
socket.to(room).emit('new_message', `${socket.nickname}: ${msg}`);
done();
});
socket.on('nickname', (nickname) => (socket['nickname'] = nickname));
});
Adapter๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก ํ๋ ์ผ์ ๋ค๋ฅธ ์๋ฒ๋ค ์ฌ์ด์ ์ค์๊ฐ ์ดํ๋ฆฌ์ผ์ด์ ์ ๋๊ธฐํ ํ๋ ๊ฒ!๐
ํ์ฌ ์ฐ๋ฆฌ๋ ์๋ฒ์ ๋ฉ๋ชจ๋ฆฌ์์ Adapter๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค์๋ ์๋ฌด๊ฒ๋ ์ ์ฅํ๊ณ ์์ง ์์. โ ์ฐ๋ฆฌ๊ฐ ์๋ฒ๋ฅผ ์ข
๋ฃํ๊ณ ๋ค์ ์์ํ ๋ ๋ชจ๋ room๊ณผ message์ socket์ ์์ด์ง๋ค.
โ โ๏ธ ์ฐ๋ฆฌ๋ ๋ฐฑ์๋์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๊ฐ์ง๊ณ ์ถ์ !!
๋ํ ์ฑ ์์ ๋ง์ ํด๋ผ์ด์ธํธ๊ฐ ์์ ๋, ๋ชจ๋ ํด๋ผ์ด์ธํธ์ ๋ํด์ connection์ ์ด์ด๋ฌ์ผํ๋ค. (์ฌํ๋ฆฌ์ ํฌ๋กฌ ๋ธ๋ผ์ฐ์ ๋ฅผ ์ฐ๋ฆฌ ์๋ฒ์ ์ฐ๊ฒฐํ๋ฏ)
โ ๊ทธ๋ฌํ ์ฐ๊ฒฐ์ ์ด๋๊ฐ์ ์์ด์ผ ํ๊ณ , ์ฆ ์ค์๊ฐ์ผ๋ก ์๋ฒ ๋ฉ๋ชจ๋ฆฌ์ ์์ด์ผ ํ๋ค.
โ ์ฆ ์๋ฒ๋ ์ด connection์ ์คํ๋ ์ํ๋ฅผ ์ ์งํด์ผ ํ๋ค.
๋ง์ ๋ธ๋ผ์ฐ์ ๋ค์ ํ๋์ ์๋ฒ์ connection๋ค์ ์ด ๊ฒ โ ์๋ฒ์ ๋ง์ connection์ด ๋ค์ด์จ๋ค.
์๋ฒ๋ ๊ทธ ๋ง์ connection๋ค์ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ ๊ฒ์ด๋ฉฐ ์๋ฒ 2 ํน์ 3๊ฐ๋ฅผ ๋ง๋ค ์๋ ์๊ฒ ๋ ๊ฒ์ด๋ค. ์ด๊ฒฝ์ฐ ๋ชจ๋ ํด๋ผ์ด์ธํธ๊ฐ ๋์ผํ ์๋ฒ์ ์ฐ๊ฒฐ๋๋ ๊ฒ์ ์๋ ์ ์๋ค.
โ ์ด๋ Adapter ๋ฅผ ์ฌ์ฉ ํด์ ์๋ฒ A์ ์๋ ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ B์ ๋ฉ์ธ์ง๋ฅผ ๋ณด๋ผ ์ ์๋ค.
Adapter๋ ์ดํ๋ฆฌ์ผ์ด์ ์ผ๋ก ํตํ๋ ์ฐฝ๋ฌธ!
Adapter๋ ๋๊ฐ ์ฐ๊ฒฐ๋์๋์ง, ํ์ฌ ์ดํ๋ฆฌ์ผ์ด์ ์ room์ด ์ผ๋ง๋ ์๋์ง ์๋ ค์ค๋ค.
const sids = new Map()
undefined
sids.set('nCc3Xbqinz2m9Pe_AAAN', true)
Map(1) {'nCc3Xbqinz2m9Pe_AAAN' => true}
sids.set('KMA__nvZDIDHjaLWAAAP', true)
Map(2) {'nCc3Xbqinz2m9Pe_AAAN' => true, 'KMA__nvZDIDHjaLWAAAP' => true}
sids
Map(2) {'nCc3Xbqinz2m9Pe_AAAN' => true, 'KMA__nvZDIDHjaLWAAAP' => true}
const rooms = new Map()
undefined
rooms.set('KMA__nvZDIDHjaLWAAAP', true)
Map(1) {'KMA__nvZDIDHjaLWAAAP' => true}
rooms.set('nCc3Xbqinz2m9Pe_AAAN', true)
Map(2) {'KMA__nvZDIDHjaLWAAAP' => true, 'nCc3Xbqinz2m9Pe_AAAN' => true}
rooms.set('seul',true)
Map(3) {'KMA__nvZDIDHjaLWAAAP' => true, 'nCc3Xbqinz2m9Pe_AAAN' => true, 'seul' => true}
rooms.forEach((_,key)=> {
if(sids.get(key) !== undefined){ // ํ๋ผ์ด๋น ๋ฃธ์ ์ฐพ์ ์ ์๋ค.
console.log(key)
}
})
// KMA__nvZDIDHjaLWAAAP
// VM10984:3 nCc3Xbqinz2m9Pe_AAAN
rooms.forEach((_,key)=> {
if(sids.get(key) === undefined){ // ํผ๋ธ๋ฆญ ๋ฃธ์ ์ฐพ์ ์ ์๋ค.
console.log(key)
}
})
// seul
// io.sockets.adapter๋ก ๋ถํฐ sids์ rooms๋ฅผ ๊ฐ์ ธ์์ ์ ์์์ ๊ฐ์ ์์
function publicRooms() {
const {
sockets: {
adapter: { sids, rooms },
},
} = io;
// const sids = io.sockets.adapter.sids; //
// const rooms = io.sockets.adapter.rooms; // ์ด ์ฝ๋ ๋์ค์ ์์ฒ๋ผ ์ ์ํ๋ ๊ฒ๊ณผ ๊ฐ๋ค
const publicRooms = [];
rooms.forEach((_, key) => {
if (sids.fet(key) === undefined) {
publicRooms.push(key);
}
});
return publicRooms;
}
// server.js
function publicRooms() {
const {
sockets: {
adapter: { sids, rooms }, // sids๋ rooms๋ฅผ io๋ก๋ถํฐ ๊ตฌ์กฐ๋ถํด ํด์ค๋ ์ฝ๋
},
} = io;
const publicRooms = [];
rooms.forEach((_, key) => {
if (sids.get(key) === undefined) {
publicRooms.push(key);
}
});
return publicRooms;
}
socket.on('enter_room', (roomName, done) => {
socket.join(roomName);
done();
socket.to(roomName).emit('์ฐ์ปด', socket.nickname); // 1)
io.sockets.emit('room_change', publicRooms()); // 2)
});
// app.js
// socket.on('room_change', (msg) => console.log(msg));์ ๊ฐ์
socket.on('room_change', console.log);
socket.on('disconnect', () => {
io.sockets.emit('room_change', publicRooms());
});
// server.js
socket.on('enter_room', (roomName, done) => {
socket.join(roomName);
done();
socket.to(roomName).emit('์ฐ์ปด', socket.nickname);
io.sockets.emit('room_change', publicRooms());
});
socket.on('disconnect', () => {
io.sockets.emit('room_change', publicRooms());
});
// app.js
socket.on('room_change', (rooms) => {
roomList.innerHTML = ''; // 2)
const roomList = welcome.querySelector('ul');
if (rooms.length === 0) { // 1)
roomList.innerHTML = '';
return;
}
rooms.forEach((room) => {
const li = document.createElement('li');
li.innerText = room;
roomList.append(li);
});
});
1) []
์ผ๋๋ ์
๋ฐ์ดํธ๋ฅผ ์ํด์ฃผ๋ฏ๋ก(?) ์ฌ์ฉ์๊ฐ ๋๊ฐ๋๋ผ๋ ๋ฐฉ ์ด๋ฆ์ด ์กด์ฌํ๋ค. ๋ฐ๋ผ์ ๋ฐฐ์ด์ ๊ธธ์ด์ ๋ฐ๋ผ ๋ณด์ฌ์ง ๋ฌธ๊ตฌ๋ฅผ ์ง์ ํด์ฃผ๋ฉด ์ฌ์ฉ์๊ฐ ๋ค ๋๊ฐ์ ๋ฐฐ์ด์ด ๊ธธ์ด๊ฐ 0์ผ๊ฒฝ์ฐ โโ
๋ฅผ ์ถ๋ ฅํ ์ ์๋ค.
2) โ๏ธํด๋น ์ฝ๋๋ฅผ ๋ฃ์ด์ฃผ์ง ์์๋๋ ๋ฐฉ์ด๋ฆ์ด ์ค๋ณต์ผ๋ก ์์ฑ ๋์๋ค. (์ธ ๊ฐ ๋ธ๋ผ์ฐ์ ์ด์์ผ๋ ํ์ธ ๊ฐ๋ฅ)
const food = new Set(['a','b','b'])
console.log(food) // Set(2) {'a', 'b'}
console.log(food.size) // 2
function countRoom(roomName) {
io.sockets.adapter.rooms.get(roomName)?.size
}
socket.on('enter_room', (roomName, done) => {
socket.join(roomName);
done();
socket.to(roomName).emit('์ฐ์ปด', socket.nickname, countRoom(roomName));
io.sockets.emit('room_change', publicRooms());
});
socket.on('disconnecting', () => { // 1)
socket.rooms.forEach((room) => // 2)
socket.to(room).emit('๋ฐ์ด', socket.nickname, countRoom(roomName)-1) // 3)
);
});
?
๋ฅผ ๋ถ์ฌ์ค๋ค.io.socketsadapter.rooms.get(roomName)
์ด๊ฒ Set์์ ์๊ณ ์์ผ๋ฏ๋ก ๋ฐ๋ก .size
ํด์ค ์ ์๋ค.1) ๋ฐฉ์ ์์ ํ ๋ ๋์ง ์์ ์ํ์ด๋ ์์ง room์ ์ ๊ทผํ ์ ์๋ค.
2) ํ์ง๋ง ์์ง ๋ฐฉ์ ๋ ๋์ง ์์์ผ๋ฏ๋ก ์ฐ๋ฆฌ๋ ํฌํจ๋์ด์ ๊ณ์ฐ๋๋ค.
3) ๋ฐ๋ผ์ -1์ ํ๋ค.
โ ์ฆ โ์ฐ์ปด' ๊ณผ โ๋ฐ์ด' ๋ฅผ ํ ๋ newCount๋ฅผ ๋ฐ๋๋ค๋ ์๋ฏธ! โ app.js (ํ๋ก ํธ์ชฝ)์์๋ ํด์ฃผ์.
socket.on('์ฐ์ปด', (user, newCount) => {
const h3 = room.querySelector('h3');
h3.innerText = `Room ${roomName} (${newCount})`;
addMessage(`${user}๋์ด ๋ค์ด์์ต๋๋ค!`);
});
socket.on('๋ฐ์ด', (left, newCount) => {
const h3 = room.querySelector('h3');
h3.innerText = `Room ${roomName} (${newCount})`;
addMessage(`${left}๋์ด ๋ ๋ฌ์ต๋๋ค ใ
ใ
...`);
});
โ๏ธ ๋ฆฌ์กํธ์ Socket.IO๋ฅผ ํ์ฉํด์ ์ฑํ ๊ธฐ๋ฅ ๊ตฌํํด๋ณด๊ธฐ
๐ ์ฌ์ฉ์ ์ ๋ณด๊ฐ ์๋จ๋ ์ด์ ํด๊ฒฐํ๊ธฐ
โ ์ ์ฌ์ฉ์ ์ ๋ณด๊ฐ ๋จ์ง ์์๊น? ๐ค
const { user } = addUser({ id: socket.id }, name, room);
const { user } = addUser({ id: socket.id, name, room });
โ๏ธ ์๋ฌ ์ญ์ถ์ !!
1) ํด๋ผ์ด์ธํธ Chat.js ์์ socket.emit โ์
์ฅโ
๋ฐ์ดํฐ ๋์ด๊ฐ๋ ๊ฑฐ ํ์ธ! โ ์ฝ์ ๋ฌธ์ ์์
2) ์๋ฒ index.js ์์ socket.on '์
์ฅ'
์์ ๋ฐ์ดํฐ ๋ฐ์์ค๋ ๊ฑฐ ํ์ธ! โ ์ฝ์ ๋ฌธ์ ์์
3) addUser์ ๊ฐ์ ์ ๋๊ธฐ๊ณ ์๋์ง ํ์ธ!! โ addUser์์ ์ฝ์ ํ์ธํ๋๋ name๊ณผ room์ด undefined๊ฐ ์ ์ฐํ!!
โ 2) ์์ ์ ๋ฐ์์์ง๋๋ฐ ์ addUser์์ ์๋๋์ง ๊ณ ๋ฏผํ๋ฉฐ ํด๊ฒฐ!!!! ๐โจ
- @socket.io/admin-ui
ํ๋ก์ ํธ ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ์ ์์ Websocket๊ณผ Socket.IO ๊ฐ๋ ์๊ณ ์ตํ๊ธฐ. ์ค์ต ํ๋ก์ ํธ !
1. JavaScript + Websocket ๐ WebSocket ์ผ๋ก ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ ํด๋ณด๊ธฐ
2. JavaScript + Socket.IO ๐ Socket.IO๋ก ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ ํด๋ณด๊ธฐ
3. React + Socket.IO ๐ Socket.IO๋ก ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ ํด๋ณด๊ธฐ
โจ with-dog ํ๋ก์ ํธ ์ฑํ ๊ธฐ๋ฅ ๊ตฌํ ๐ ์ฑํ ๊ธฐ๋ฅ ๊ตฌํํ๊ธฐ
reference) websocket, socket.io