본문 바로가기
Web Service/NodeJS

[ZOOM 클론 코딩] #4. SocketIO

by junnykim 2022. 8. 31.

~2.3까지의 강의

 

SocketIO

- 쉽게 실시간 기능을 만들어주는 프레임워크
- 실시간, 양방향, event 기반의 통신 가능

- 탄력성, 신뢰성, 빠른 속도
- 연결이 끊어지면 재연결을 시도할 것

WebSockets과 굉장히 비슷하지만, WebSockets을 사용해서 통신 기능을 사용하는 것이다.

즉, WebSockets에 문제가 생겨도 계속 진행할 수 있으며 부가기능이 아니다.

 


SocketIO를 사용해서 서버를 만들어볼 것이다.

제대로 비교해보기 위해서, server.js에 있는 것들을 주석처리를 해준다.

 

SocketIO를 설치방법

1. npm i socket.io
2. import SocketIO from "socket.io"; (server.js)
WebSocket을 생각해보면, 서버를 만들기 전에 먼저 http 서버를 만들었고, http를 위에 쌓아올리면서 만들었다.
SocketIO을 사용할 때도 마찬가지로 import를 해준다.
그리고 io서버를 만들어 준다.
3. const httpServer = http.createServer(app);
const wsServer = SocketIO(httpServer);

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

이렇게 해도 동일하다.

 

home.pug

더이상 public chat을 사용하지 않을 것이기 때문에, main에 작성된 코드들을 전부 삭제한다.

그 후, SocketIO를 설치하기 위해서 script(src="/socket.io/socket.io.js")를 추가한다.

웹소켓과 굉장히 비슷하다는 것을 알 수 있다.

 

app.js로 가서, 작성했던 코드들을 모두 삭제해준 후, 연결을 하기 위해 const socket = io();를 추가해준다.

 

server.js

wsServer.on("connection", (socket) => {
  console.log(socket);
});

webSocket방식과 동일하다.

SocketIO를 설치해주면, 화면에서 io라는 function을 볼 수 있다.

또한 자동으로 추적하고 있어서 쉽게 소켓에서 SocketIO를 확인할 수 있다.

 


room?

use가 웹사이트로 가면 방에 참가할 수 있거나 추가할 수 있게 하는 것이다.

SocketIO는 이미 room기능이 있어서 방에 참가하고 떠나는 것이 매우 간단하다.

 

먼저 fe먼저 만들어보도록 합니다.

 

home.pug

div#welcome
	form
		input(placeholder="room name", required, type="text")
		button Enter Room

div안에 form을 만든다.

이미 만들어진 방에 참가하는 것과, 방을 여는 것에는 별 차이가 없다.

즉, 방의 유무와 상관없이 존재하지 않으면 새로 만드는 것이고, 존재하면 참가하는 것이다.

FE 완료!

 

app.js

const socket = io();

const welcome = document.getElementById("welcome");
const form = welcome.querySelector("form");

function handleRoomSubmit(event) {
  event.preventDefault();
  const input = form.querySelector("input");
  socket.emit("enter_room", { payload: input.value }, () => {
    console.log("server is done!");
  });
  input.value = "";
}

form.addEventListener("submit", handleRoomSubmit);

welcom 밑에 form에 해당하는 것을 가지고 온다. 

주목해야 할 것은, WebSocket과는 다르게 socket.send가 아닌 socket.emit이다.

즉, 원하는 것을 emit 해주면 된다.

 

WebSocket의 경우 object에서 string으로 바꿔주어야 했는데, 그냥 SocketIO가 해준다.

 

SocketIO

1. 어떠한 이름이든 상관 없이, 특정한 event를 emit해줄 수 있다.
2. 전처럼 string만 전송할 필요가 없이, object를 변경할 수 있다. 

 

server.js

wsServer.on("connection", (socket) => {
  socket.on("enter_room", (msg, done) => {
    console.log(msg);
    setTimeout(() => {
      done();
    }, 10000);
  });
});

그러면 msg를 받을 수 있다. socket.on message처럼 사용하지 않는다.

이제 socketIO는 상관이 없다. 

string이 아니라 JS object이다.

이렇게 socketIO를 이용해서 메시지를 보내고 있다.

 

방을 치고 들어가면 10초안에 fe에서 함수를 실행시킬 것이다.

서버는 be에서 함수 호출하지만, 함수는 fe에서 실행된 것이다.

 


socketIO를 설치하고, 많은 새로운 기능들이 많이 생겼다.

이제 emit의 argument를 알아보자.

전에는 message만 보낼 수 있었지만, socketIO를 사용하면, 모든 것이 message일 필요가 없다.

대신 clinet는 원하는 어떠한 event를 모두 emit해줄수 있다.

즉, 전송할 때 우리가 원하는 아무거나 전송할 수 있다.

 

그 전에는 text만 전송할 수 있었지만, 이제는 원하는 만큼, 여러가지의 argument를 보낼 수 있다.

원하는 어떤 것이든지 전송할 수 있다. 내가 원하는 만큼 be에 보낼 수 있다.

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

 

app.js

function backendDone(msg) {
  console.log(`The backend says: `, msg);
}

function handleRoomSubmit(event) {
  event.preventDefault();
  const input = form.querySelector("input");
  socket.emit("enter_room", input.value, backendDone);
  input.value = "";
}

 

be에 끝난다는 사실을 알리기위해 함수를 넣고 싶으면, 그 함수가 가장 마지막 argument가 되어야 한다.

 

server.js

wsServer.on("connection", (socket) => {
  socket.on("enter_room", (roomName, done) => {
    console.log(roomName);
    setTimeout(() => {
      done("hello from the backend");
    }, 15000);
  });
});

backendDone 함수를 be에 보내고 있다. be는 두개의 argument를 받는다.

신뢰하지 못하는  코드는 be에서 하는 것이 아니기 때문에, fe에서 실행버튼을 눌러주어야 한다.

즉 fe에서 실행는 코드는 be가 실행을 시킨 것이다.

emit의 마지막 argument가 function이기만 하면 된다.

 

 

전체코드

app.js

더보기
const socket = io();

const welcome = document.getElementById("welcome");
const form = welcome.querySelector("form");

function backendDone(msg) {
  console.log(`The backend says: `, msg);
}

function handleRoomSubmit(event) {
  event.preventDefault();
  const input = form.querySelector("input");
  socket.emit("enter_room", input.value, backendDone);
  input.value = "";
}

form.addEventListener("submit", handleRoomSubmit);

server.js

더보기
import http from "http";
import SocketIO from "socket.io";
import express from "express";

const app = express();

app.set("view engine", "pug");
app.set("views", __dirname + "/views");
app.use("/public", express.static(__dirname + "/public"));
app.get("/", (_, res) => res.render("home"));
app.get("/*", (_, res) => res.redirect("/"));

const httpServer = http.createServer(app);
const wsServer = SocketIO(httpServer);

wsServer.on("connection", (socket) => {
  socket.on("enter_room", (roomName, done) => {
    console.log(roomName);
    setTimeout(() => {
      done("hello from the backend");
    }, 15000);
  });
});
  
  /*
  const sockets = [];
  
wss.on("connection", (socket) => {
    sockets.push(socket);
    socket["nickname"] = "Anon";
    console.log("Connected to Browser ✅");
    socket.on("close", onSocketClose);
    socket.on("message", (msg) => {
      const message = JSON.parse(msg);
      switch (message.type) {
        case "new_message":
          sockets.forEach((aSocket) =>
            aSocket.send(`${socket.nickname}: ${message.payload}`)
          );
        case "nickname":
          socket["nickname"] = message.payload;
      }
    });
  });*/

  const handleListen = () => console.log(`Listening on http://localhost:3000`);
  httpServer.listen(3000, handleListen);

home.pug

더보기
doctype html
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(http-equiv="X-UA-Compatible", content="IE=edge")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Noom
        link(rel="stylesheet", href="https://unpkg.com/mvp.css")
    body
        header
            h1 Noom
        main
            div#welcome
                form
                    input(placeholder="room name", required, type="text")
                    button Enter Room
        script(src="/socket.io/socket.io.js") 
        script(src="/public/js/app.js")

'Web Service > NodeJS' 카테고리의 다른 글

[ZOOM 클론 코딩] #3. Chat & Nicknames  (4) 2022.08.24
[ZOOM 클론 코딩] #2. WebSockets  (0) 2022.08.04
[ZOOM 클론 코딩] #1. Set up  (0) 2022.07.30

댓글