newChobo
article thumbnail
Published 2023. 2. 15. 00:58
줌 클론코딩 #2 SOCKETIO 공부/NodeJS

1. #2.0 SocketIO vs WebSockets (07:20)

SOCKET.IO 에 대해 배워보자.

실시간, 양방향, event 기반 통신 가능하게 함.

 

Socket IO는 websocket을 실행하는게 아니다.

Socket IO는 framework, 실시간 + 양방향 + event 기반 통신

websocket보다 탄력성이 뛰어나다?

 

웹소켓이 안되도 socket IO는 작동을 한다.(?)

Socket IO는 websocket을 가끔 써서 기능 제공하는 프레임워크다. websocket없어도 기능제공한다.

websocket 지원 안하면 HTTP long polling같은것을 사용한다고 한다.

 

Socket IO는 인터넷이 잠깐만 끊겨도 재 연결을 시도한다.

우리는 필요하면 직접 만들어내야 한다.

 

웹 소켓보다 조금더 무거움. 웹소켓은 기능 자체가 얼마 없으니.

그래도 그렇게 무겁지는 않음.

 

2. #2.1 Installing SocketIO (07:51)

http://localhost:3000/socket.io/socket.io.js

서버에 socketIO 설치한것처럼 클라이언트에도 socketIO 설치 필요.

브라우저 websocket은 socket IO와 호환이 안되기 때문.

 

이번엔 익명채팅말고 방을 만들어보자.

server.js

<javascript />
//connection 받을 준비 끝 wsServer.on("connection", (socket) => { console.log(socket); });

 

스크립트 다운로드하면 io 라는 함수를 볼 수 있다.

자동적으로 back-end 의 socket.io와 연결해주는 function이다.

 

app.js

const socket = io();

를 해주게 되면 io function은 알아서 socket.io를 실행하는 서버를 찾는다.

 

이젠 쉽게 socket의 id도 확인할 수 있다.

https://github.com/NewChoBo/zoom/commit/a1edc325f413d88eccebf6e4686e932db425296d

 

 

3. #2.2 SocketIO is Amazing (10:15)

socket IO에는 이미 room 기능이 있다.

자바스크립트 객체를 직접 보낼 수 있다.

 

Callback은 서버로부터 실행되는 function.

 

app.js

 
<javascript />
socket.emit("enter_room", { payload: input.value }, () => { console.log("server is done!"); });

3번째 인자는 서버에서 호출함

 

Socket.emit 에 대한 설명 (순서에 따른 인자)

1: event 이름 - text -> 당연히 백엔드 socket.on("~~~", ~~)의 이름과 같은 이름, 같은 String이어야 함.

2: 보내고 싶은 payload(아마 데이터 인듯)

3: 서버에서 호출하는 function (함수)

 

서버로부터 function을 호출.

근데 function은 front-end에 있다.

 

socket.on("name", (msg, done) => {console.log("hi"); done;});

1: event 이름

2-1: 받아온 데이터

2-2: 호출할 함수(프론트엔드의)

 

Socket.emit / Socket.on

<javascript />
app.js socket.emit("enter_room", { payload: input.value }, () => { console.log("server is done!"); }); server.js wsServer.on("connection", (socket) => { socket.on("enter_room", (msg, done) => { console.log(msg); setTimeout(() => { done(); }, 10000); }); });

back-end에서 10초 후에 함수를 호출하고, 함수는 front-end에서 실행되게 된다.

console.log는 프론트엔드에서 찍힌다.

https://github.com/NewChoBo/zoom/commit/e4e49346a25d7dc027362fd247e0029362afbec6

 

4. #2.3 Recap (11:55)

이전에는 String만 보낼 수 있었다.

그래서 JSON으로 parse하고 어쩌고 하는 수고가 필요했다.

 

하지만, socketIO를 사용하게 된다면 어떤 event든 모두 emit 할 수 있다.

back-end에서 프론트엔드가 함수를 실행하도록 할 수 있다.

 

서버와 연결 끊기면 재연결 시도

인자를 여러개 보낼 수도 있고, 또 클라이언트 호출 함수(Callback)가 없어도 됨.

<javascript />
app.js socket.emit( "enter_room", { payload: input.value }, 5, "hello", 43443, true, false ); server.js wsServer.on("connection", (socket) => { socket.on("enter_room", (a, b, c, d, e, f) => { console.log(a, b, c, d, e, f); }); });

 

 

근데 여러 인자일때 callback 함수는 어떻게 구분하지...?

 

끝날때 실행되는 function을 보내고 싶으면 마지막에 넣어야 한다.

function은 백엔드에서 실행되지 않고 프론트에서 실행된다.

그저 프론트에 실행하라고 말하는 것?

 

+++ 서버 재실행되도 계속 소켓이 연결되어있는 모습...

<javascript />
app.js function backendDone(msg){ console.log(`The backend says : ${msg}`); } --- socket.emit( "enter_room", { payload: input.value }, backendDone, ); server.js wsServer.on("connection", (socket) => { socket.on("enter_room", (roomName, done) => { console.log(roomName); setTimeout(() => { done("hello from the backend!"); }, 5000); }); });

https://github.com/NewChoBo/zoom/commit/984d48832a0540c6bb050f393a6534f3c0074afb

 

5. #2.4 Rooms (11:35)

Chat rooms를 만들때 socketIO가 제공하는 기능 좋아하게 될 것.

chat rooms 말고 어떤 room이든 상관 없다.

요점은 서로 통신하는 방이 있어야 한다.

 

Websocket에서는 room이 중요했다.

 

socket.io는 room을 제공한다.

단순히 socket.join(roomName);  을 하면 끝이다.

https://socket.io/

 

Socket.IO

Reliable Rest assured! In case the WebSocket connection is not possible, it will fall back to HTTP long-polling. And if the connection is lost, the client will automatically try to reconnect.

socket.io

 

socket.rooms -> socket이 어떤 방에 있는지 알 수 있다.

 

console.log(socket.rooms)를 했을 때...

<javascript />
console.log(socket.id); //SzpesOujlPXG2-0kAAAD console.log(socket.rooms); //Set(1) { 'SzpesOujlPXG2-0kAAAD' } socket.join(roomName); console.log(socket.rooms); //Set(2) { 'SzpesOujlPXG2-0kAAAD', 'room1' }

 

-> 첫번째 방은 socket id인 것을 알 수 있다.

왜냐면 socket.io의 모든 socket은 User와 서버 사이에 private room이 있다.

 

방에 들어가려면 socket.join 하면 된다.

socket이 어떤 방에 있는지 아려면 socket.room를 하면 된다.

<javascript />
socket.onAny((event) => { console.log(`Socket Event:${event}`); //Socket Event:enter_room // console.log(`You are in room : ${JSON.stringify(socket.rooms)}`); //이건 아닌가봄. })

 

socket.join(["room 237", "room 238"]);   //한번에 여러개의 방에도 참여할 수 있다.

socket.rooms는 집합인건지, 여러번 join해도 한번만 된다.

 

leave room

socket.leave("room 237");

 

room 안의 모두에게 메세지(백엔드->프론트or백엔드)

//방 하나

socket.to(room).emit("an event", { some: "data" });

 

//방 여러개

socket.to("room1").to("room2").emit("hello");

 

//배열로 방 여러개

socket.to(["room1","room2"]).emit("hello");

 

위 코드를 활용해서 방의 모두에게 알림.

https://github.com/NewChoBo/zoom/commit/2927fe16890942e28b9b1bafae5e6e6105103db5

 

6. #2.5 Room Messages (07:01)

documentation을 보면서 방금 들어간 방 안에 있는 모든 이에게 메세지 전송

 

다른 socket의 ID를 알고있다면, Private Message를 보낼 수 있다.

 

// a private message to another socket

socket.to(/* another socket id */).emit("key");

 

----------------------------------------------------------------------

 

app.js

addEventListener 사용하지 않는다.

socket.on을 우리가 원하는 대로 사용한다.

 

socket.to(roomName).emit(~~~) 는 방의 모두에게 메세지를 보내지만 자기 자신에게는 보내지 않는다.

서로 다른 브라우저로 테스트해봤더니 됨. 근데 같은 브라우저 다른 탭이여도 되네..?

 

다음 시간에 메세지와 notification을 구현할 것.

https://github.com/NewChoBo/zoom/commit/d6315a8471b136110b10e5b9356801559c22389a

 

7. #2.6 Room Notifications (13:20)

방에서 퇴장했다는것도 알려줘야 함.

 

server.js

바로, disconnecting

disconnect와 다름.

 

Disconnecting은 client가 접속을 중단할 것이지만, 아직 나가지는 않은 상태.

우리가 완전히 끊기기 전에(창을 닫거나, 컴이 꺼졌을 때 우리는 방에 message를 보낼 수 있다.)

 

이건 클라이언트와 서버와 연결이 끊어지기 전에 마지막 "굿바이" message를 보낼 수 있다.

라는데 갑자기 끊긴 돌발상황은 어떻게 되는거지? 방안의 나머지 참가자에게만 영향을 미치는건가?

 

다른 클라이언트가 접속이 끊긴것은 확인할 수 있다.

그럼 떠나기 전에 라기보다는 그냥 다른 사람의 연결이 끊긴것을 감지하는 코드일 뿐인가?

 

그 전에 잠깐!

<javascript />
app.js const form = room.querySelector("form"); //document.querySelector와 달라서 뭔가 했었음 //하지만, 앞서서 const room = document.getElementById("room"); 를 해준 적이 있음. //문서의 room 안에서 querySelector을 돌리는 것.

 

<javascript />
app.js socket.on("new_message", (msg) => addMessage(msg + '-익명함수')); socket.on("new_message", addMessage); // socket.on("new_message", addMessage(msg)); //socket.on 을 여러개 등록해줘도 한번만 작동하는 모습인줄 알았는데, 함스 자체를 잘못 사용

 

<javascript />
app.js function handleMessageSubmit(event){ event.preventDefault(); const input = room.querySelector("input"); const value = input.value; socket.emit("new_message", input.value, roomName, () => { addMessage(`You: ${value}`); }); //이벤트 이름은 상관 없음. input.value = ""; } //동기식으로 처리되서 그런건지, addMessage 함수가 input.value="" 보다 늦게 처리되는 것으로 보임.

 

//다음 영상에서는 socket에 닉네임. 그리고, 방안에 얼마나 많은 사람이 있나 세볼 것.

https://github.com/NewChoBo/zoom/commit/db8b366e5382b89ac9b65eea5f74ccabaf2f5591

 

8. #2.7 Nicknames (09:44)

<javascript />
server.js //여기서도 그냥 websocket 쓸때와 동일하게 socket 안에 데이터를 저장할 수 있다. socket.on("nickname", nickname => socket["nickname"] = nickname); ~~ //websocket 내의 데이터 접근 socket.on("enter_room", (roomName, done) => { socket.join(roomName); done(); socket.to(roomName).emit("welcome", socket.nickname); }); socket.on("disconnecting", () => { socket.rooms.forEach( room => socket.to(room).emit("bye", socket.nickname) ); }); socket.on("new_message", (msg, roomName, done) => { socket.to(roomName).emit("new_message", `${socket.nickname}: ${msg}`); done(); });

 

##코드챌린지

지금은 유저가 접속하면 항상 Anonymous

 

방에 입장하기 전에 방 이름과 nickname을 물어보도록??

nickname form을 room 밖으로 옮길 수 있을것.

 

//코드챌린지 전

https://github.com/NewChoBo/zoom/commit/818284f807357f94c5ebf6bc9adeb3cddc63378a

 

//코드챌린지 후

https://github.com/NewChoBo/zoom/commit/8c9559b6bcf78e095d6792cd2eab3463a78a89c5

 

9. #2.8 Room Count part One (15:23)

이번엔 Apdapter라는 개념에 대해서 알아볼 것.

Adapter은 기본적으로 다른 서버들 사이에 실시간 어플리케이션을 동기화

 

지금 우리는 서버에서 adapter을 사용하고 있었음.

db에는 아무것도 저장하지 않음.

 

현재는 앱 안에 많은 클라이언트가 있으면 모두 연결해놔야 함. 실시간으로 서버메모리에 있어야 함.

그리고, 이 서버메모리는 다른 서버와 같은 memory pool을 공유하지 않음.

 

이를 해결하기 위해 Adapter 사용(MongoDB같은)

console.log(wsServer.sockets.adapter);    //???

 

//사전자료형 Map?

모든 sids에 대한 map을 만들것.

 

map을 반복하거나 살펴보기

rooms.forEach((value, key) => console.log(value, key));     //value는 같을 수 있음. key는 모두 다름

 

map 안에 있는것을 어떻게 가져올까?

근데 private값은 못가져옴(?)

<javascript />
...? 현재 서버에 있는 모든 room을 보여주고 싶어서...? sids.get(key)를 통해서 key가 socket ID인지 방제목인지 알 수 있다. 만약 내가 room의 key와 함께 socket ID를 가질 수 있다면? sids는 id 목록인거? sids는 백엔드에 연결된 모든 socket들의 map이다. rooms중 socketid에 해당하는 애들도 포함되어있다. 그걸 제외하면 방제목일것. rooms.forEach((_, key) => { //if(sids.get(key) !== undefined){ //undefined와 같지 않다면, private이다. if(sids.get(key) === undefined){ //undefined와 같다면, public 이다. console.log(key); //==>> private가 아닌 방은 출력 } }

/*

ㅋㅋㅋㅋㅋ 요약: sids에는 개인방, rooms에는 개인방,공개방 다있음.
rooms가 sids를 포함한다 보면됨.
그래서 공개방만 얻고 싶을때는 rooms에서 sids를 빼면 됨

*/

 

<javascript />
//publicRooms만 골라낸다. (socket id 걸러내기) function publicRooms(){ const { sockets: { adapter: {sids, rooms }, }, } = wsServer; //이 문법은 많이 낯설다. // const sids = wsServer.sockets.adapter.sids; // const rooms = wsServer.sockets.adapter.rooms; const publicRooms = []; rooms.forEach((_, key) => { if(sids.get(key) === undefined){ publicRooms.push(key); } }) return publicRooms; }

https://github.com/NewChoBo/zoom/commit/bd69119d804d60829b20f35c699d9754021896c7

10. #2.9 Room Count part Two (08:10)

이번 시간에는 새로운 방이 만들어졌다고 모두에게 알릴 것.

socket.to(~~).emit(~~~)이 아니라, server.sockets.emit을 사용할 것.

이건 message를 모두에게 보내는 것.

 

연결된 모든 socket에게.

 

누군가가 방에 진입하면, 공지를 내보낼 것.

우리 애플리케이션 안에 있는 모든 방에.

근데 한 브라우저에 여러 창 띄우는건 뭔가 오류 여지가 있는거같기도 하고

 

disconnecting <-> disconnect

 

room paint?

https://github.com/NewChoBo/zoom/commit/ddca5c794b566aa32ac61477a8d0e86b902793dc

 

11. #2.10 User Count (07:26)

마지막으로 방 안의 인원수를 세는 것.

방들은 소속된 인원들을 set으로 갖고있음.

 

set의 size 알아내는 법?

<javascript />
const food = new Set([ "pizza", "love", "love" ]); console.log(food); //Set(2) {"pizza", "love"} console.log(food.size); //2

 

방 안 인원수

 

socket.on, callback,..

https://github.com/NewChoBo/zoom/commit/18f5f37992ea16dcb2417f36be0ba3240d3ddf64

 

12. #2.11 Admin Panel (06:13)

Admin UI? socket.IO  백엔드를 위한 것?

https://socket.io/docs/v4/admin-ui/

백엔드를 위한 UI

 

여기서 모든 socket, room, client를 확인할 수 있다.

 

설치는

npm i @socket.io/admin-ui

vs code에서 하면 오류 발생 => npm i "@socket.io/admin-ui"

https://nomadcoders.co/noom/lectures/3106/comments/58173

 

설치 후에 instrument라는걸 import하면 된다.

그리고 우리가 socket.io를 만든 방식도 조금 바꿔야 한다.

-server.js-

const { Server } = require("socket.io");      //예제 코드는 이렇게 되있었음

const { instrument } = require("@socket.io/admin-ui");

 

admin.socket.io 링크 접속하면 서버 연결하는 입력창 나옴

Server url : http://localhost:3000/admin

user name : 

password : 

path : 

다 비워도 됨.

 

https://nomadcoders.co/noom/lectures/3106/comments/119479

 

gui가 상당히 잘 되어있네요...

https://github.com/NewChoBo/zoom/commit/591a38918c08c9d852adfb011d71fb66a755abbe

 

 

'공부 > NodeJS' 카테고리의 다른 글

줌 클론코딩 #3 VIDEO CALL  (0) 2023.02.16
줌 클론코딩 #1 CHAT WITH WEBSOCKETS  (0) 2023.02.13
줌 클론코딩 #0 INTRODUCTION  (0) 2023.02.12
profile

newChobo

@새로운뉴비

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!