disconnect는 완전히 연결이 끊긴거, disconnecting은 고객이 접속을 중단할 것이지만 아직 방을 완전히 나가지는 않은것.
socketServer.on("connection", (socket) =>{
// console.log(socket);
socket.onAny((event)=>{
console.log(`Socket Event: ${event}`);
})
socket.on("enter_room", (roomName,done) => {
// console.log(roomName);
// console.log(socket.rooms)
socket.join(roomName)
// console.log(socket.rooms)
done()
socket.to(roomName).emit("welcome")
})
socket.on("disconnecting",() => {
socket.rooms.forEach(room => socket.to(room).emit("방을 나갑니다."))
})
})
클라이언트가 서버와 연결이 끊어지기 전에 “방을 나갑니다.”라는 message를 보낼 수 있음.
socket.on("bye", () =>{
addMessage("누군가 방에서 나갔습니다.")
})
방안에 있는 사람들에게 메세지 보내는 코드 구현
function handleMessageSubmit(event) {
event.preventDefault();
const input = room.querySelector("input");
socket.emit("new_message", input.value,roomName, ()=>{
addMessage(`You : ${input.value}`);
});
input.value = "";
}
function showRoom() {
welcome.hidden=true;
room.hidden=false;
const h3 = room.querySelector("h3");
h3.innerText = `Room ${roomName}`;
const form = room.querySelector("form");
form.addEventListener("submit",handleMessageSubmit);
}
socket.on("new_message",addMessage);
socket.on("new_message", (msg,room,done)=>{
socket.to(room).emit("new_message",msg);
done()
})
이제 채팅할때 닉네임을 추가해보자!
function handleMessageSubmit(event) {
event.preventDefault();
const input = room.querySelector("#msg input");
const value = input.value;
socket.emit("new_message", input.value,roomName, ()=>{
addMessage(`You : ${value}`);
});
input.value = "";
}
function handleNicknameSubmit(event) {
event.preventDefault();
const input = room.querySelector("#name input");
socket.emit("nickname",input.value)
}
function showRoom() {
welcome.hidden=true;
room.hidden=false;
const h3 = room.querySelector("h3");
h3.innerText = `Room ${roomName}`;
const nameForm = room.querySelector("#name");
const msgForm = room.querySelector("#msg");
msgForm.addEventListener("submit",handleMessageSubmit);
nameForm.addEventListener("submit",handleNicknameSubmit);
}
socket.on("nickname", nickname => socket["nickname"] = nickname)
추가로 강제로 방에 입장시킬수도 있음.
wsServer.socketsJoin("익명");
adapter ?
기본적으로 하는 일은 다른 서버들 사이에 실시간 어플리케이션을 동기화 함.
우리는 서버의 메모리에서 adapter를 사용하고 있음. Database에는 아무것도 저장하고 있지 않음. (서버를 종료하고 다시시작하면 모든 Room과 mesaage, socket은 사라짐)
만약 우리가 adapter를 사용하지 않는다면 서버 A에 있는 클라이언트가 서버B에 있는 클라이언트에 메세지를 보낼 수 없음! (두 서버는 분리되어 있기 때문)
adapter는 몽고디비와 같은 애들을 사용하여 서버간의 통신을 하게 해줌. 서버A에서 서버B로 메세지를 보내려면 서버A에서 adapter와 데이터베이스를 거쳐 다시 adapter로 간 후에 서버B에게 보내짐.

⇒ 이 adapter를 사용하여 누가 연결되어 있는지, 현재 어플리케이션에 Room이 얼마나 있는지를 알 수 있음!
socket.onAny((event)=>{
console.log(socketServer.sockets.adapter);
console.log(`Socket Event: ${event}`);
})
rooms: Map(1) {
'0LNJQBiDM6q1HZ3qAAAD' => Set(1) { '0LNJQBiDM6q1HZ3qAAAD' }
},
sids: Map(1) {
'0LNJQBiDM6q1HZ3qAAAD' => Set(1) { '0LNJQBiDM6q1HZ3qAAAD' }
},
rooms는 어플리케이션에 있는 모든 rooms을 볼 수 있음.
sids는 socket id를 볼 수 있음.
⇒ sids에는 개인방, rooms에는 개인방,공개방 다있고 rooms가 sids를 포함한다 보면됨!
function publicRooms() {
const {sockets : {adapter : { sids, rooms}} } = socketServer;
// const sids =socketServer.sockets.adapter.sids;
// const rooms = socketServer.sockets.adapter.rooms;
const publicRooms =[];
rooms.forEach((_,key)=>{
if(sids.get(key) === undefined){
publicRooms.push(key)
}
})
return publicRooms
}
새로운방이 생겼다고 연결된 모든 socket 모두에게 보내주기! server.sockets.emit을 사용
socket.on("room_change",(rooms) =>{
const roomList = welcome.querySelector("ul");
if(rooms.length === 0){
roomList.innerText = "";
return;
}
rooms.forEach(room => {
const li = document.createElement("li");
li.innerText=room;
roomList.append(li);
});
});
socket.on("enter_room", (roomName,done) => {
// console.log(roomName);
// console.log(socket.rooms)
socket.join(roomName)
// console.log(socket.rooms)
done()
socket.to(roomName).emit("welcome", socket.nickname)
socketServer.sockets.emit("room_change",publicRooms());
})
socket.on("disconnect",() => {
socketServer.sockets.emit("room_change",publicRooms());
})
우리 방 안에 있는 사람들의 수를 세보자!
⇒ 한 방에 몇명이 있는지 계산하기 위해서는 rooms로 가서 우리가 찾고있는 room 의 key를 얻고, set.size로 크기를 얻어주면 됨!
function countRoom(roomName) {
return socketServer.sockets.adapter.rooms.get(roomName)?.size;
}
socket.on("enter_room", (roomName,done) => {
// console.log(roomName);
// console.log(socket.rooms)
socket.join(roomName)
// console.log(socket.rooms)
done()
socket.to(roomName).emit("welcome", socket.nickname, countRoom(roomName))
socketServer.sockets.emit("room_change",publicRooms());
})
socket.on("disconnecting",() => {
socket.rooms.forEach(room => socket.to(room).emit("bye", socket.nickname,countRoom(room) -1))
socketServer.sockets.emit("room_change",publicRooms());
})
socket.on("welcome", (user,newCount) =>{
addMessage(`${user}님이 방에 들어왔습니다!`)
const h3 = room.querySelector("h3");
h3.innerText = `Room ${roomName} (${newCount}명 참가중)`;
})
socket.on("bye", (user,newCount) =>{
addMessage(`${user}님이 방에서 나갔습니다.`)
const h3 = room.querySelector("h3");
h3.innerText = `Room ${roomName} (${newCount}명 참가중)`;
})
socket.IO 백엔드를 위한 admin UI가 있음! 모든 Room과 클라이언트를 확인할 수 있음.
npm i @socket.io/admin-ui
import { instrument } from "@socket.io/admin-ui";
const socketServer = new Server(httpServer,
{cors: {
origin: ["https://admin.socket.io"],
credentials: true
}}
);
instrument(socketServer, {
auth: false,
mode: "development",
});
