카테고리 없음

[Nomad/zoom clone coding Challenges] 1일차 | Ch01 CHAT WITH WEBSOCKETS

루이란 2022. 6. 14. 22:51
728x90

참고자료: 노마드 코더 줌 클론코딩 https://nomadcoders.co/noom/lobby

 

1 HTTP vs WebSockets


👉🏻HTTP 서버는 유저에게 먼저 말을 걸 수 없다. client가 요청하면 response 과정 이후 유저가 누구인지 잊어버린다.

👉🏻웹소켓(ws)에서는 서버와 유저가 연결되어 있기 때문에 유저가 요청하면 서버가 답장할 수 있고 먼저 말을 걸 수도 있다. 

 

2.  WebSockets in NodeJS


server.js
const server = http.createServer(app); 
const wss = new WebSocketServer({ server });

👉🏻express는 http 프로토콜을 다루는데 우리는 둘 다 다루기 위해 위와 같은 작업을 해분다.

  • http 서버를 만든다. 이렇게 해야 서버에 접근 가능하다.
  • 웹소켓 서버를 만들고 http 서버와 함께 둘 다 작동시킨다. 웹소켓 서버만 구동시키고 싶으면 {server} 인자를 안 넘겨주면 된다.

 

3.  WebSockets Events


server.js
function handleConnection(socket) { 
    console.log(socket);
  }
wss.on("connection", handleConnection);

✍🏻on: JS의 addEventListener와 같은 역할을 한다. connection이라는 행동을 하면 해당 함수를 실행한다.

👉🏻socket에 이벤트에 대한 정보를 담아준다.

app.js
const socket = new WebSocket(`ws://${window.location.host}`);

👉🏻서버로 접속한다.

 

4.  WebSockets Messages


 

server.js
wss.on("connection", (socket) => {
    console.log("Connected to Browser ✅");
    socket.on("close", () => console.log("Disconnected from the Browser ❌")); //브라우저에서 열결이 끊기면 실행한다.
    socket.on("message", (message) => {
      console.log(message);
    });
    socket.send("hello!!!"); //send로 데이터를 보낸다.
});

👉🏻connection listener를 정의하면 브라우저와 연결이 되었을 때 실행한다.

👉🏻close listener를 정의하면 브라우저와 연결이 끊겼을 때 실행한다.

👉🏻message listener를 정의하면 브라우저에서 메시지가 왔을 때 실행한다.

👉🏻socket.send를 이용해 브라우저로 데이터를 보낸다.

app.js
socket.addEventListener("open", () => {
    console.log("Connected to Server!")
}) 

socket.addEventListener("message", (message) => {
    console.log("New message: ", message.data);
}); 
  
  socket.addEventListener("close", () => {
    console.log("Disconnected from Server ❌");
});

setTimeout(() => {
    socket.send("hello from the browser!");
}, 10000);

👉🏻open listener를 정의하면 서버와 연결이 되었을 때 실행한다.

👉🏻close listener를 정의하면 서버와 연결이 끊겼을 때 실행한다.

👉🏻message listener를 정의하면 서버에서 메시지가 왔을 때 실행한다.

👉🏻socket.send를 이용해 서버로 데이터를 보낸다.

 

💡이 연결은 alive하다!

 

6.  Chat Completed


 

home.pug
main
    ul
    form
        input(type="text", placeholder="write a msg", required)
        button Send
server.js
const sockets = [];

function onSocketClose() {
    console.log("Disconnected from the Browser ❌");
}

wss.on("connection", (socket) => {
  sockets.push(socket);
  console.log("Connected to Browser ✅");

  socket.on("close", onSocketClose);

  socket.on("message", (message) => {
    sockets.forEach((aSocket) => aSocket.send(message.toString()));
  });
});

👉🏻브라우저에서 받은 메시지를 다시 돌려보낸다.

👉🏻연결된 모든 소켓에 접근하기 위해 forEach를 사용한다. 크롬에게 받으면 크롬에게만 보내고 파이어 폭스에게 받으면 파이어폭스에게만 돌려보내는 현상을 방지하기 위함이다.

app.js
const messageList = document.querySelector("ul");
const messageForm = document.querySelector("form");

...

function handleSubmit(event) { 
    event.preventDefault();
    const input = messageForm.querySelector("input");
    socket.send(input.value); 
    input.value = "";
}
  
messageForm.addEventListener("submit", handleSubmit);

👉🏻폼의 제출버튼을 누르면 handlSubmit 함수를 실행한다. input의 value를 server로 보낸다.

 

7-8.  Nicknames part One-Two


 

home.pug
main
    form#nick
        input(type="text", placeholder="choose a nickname", required)
        button Save
    ul
    form#message
        input(type="text", placeholder="write a msg", required)
        button Send

👉🏻닉네임을 저장할 form과 메시지를 보낼 form을 만든다.

app.js
const messageList = document.querySelector("ul");
const nickForm = document.querySelector("#nick");
const messageForm = document.querySelector("#message");

const socket = new WebSocket(`ws://${window.location.host}`);

socket.addEventListener("open", () => {
    console.log("Connected to Server!")
});

socket.addEventListener("close", () => {
    console.log("Disconnected from Server ❌");
});

👉🏻폼들을 변수로 지정하고 소켓에 접속한다.

function makeMessage(type, payload) {
    const msg = { type, payload };
    return JSON.stringify(msg);
}

👉🏻닉네임이나 메시지를 보내면 서버에 보낼 json으로 변환하는 함수를 만든다.

socket.addEventListener("message", (message) => {
    const li = document.createElement("li");
    li.innerText = message.data;
    messageList.append(li);
});

👉🏻서버에서 받은 메시지를 li tag에 담아 브라우저에서 출력해준다.

function handleSubmit(event) { 
    event.preventDefault();
    const input = messageForm.querySelector("input");
    socket.send(makeMessage("new_message", input.value)); 
    input.value = "";
}

function handleNickSubmit(event) {
    event.preventDefault();
    const input = nickForm.querySelector("input");
    socket.send(makeMessage("nickname", input.value));
    input.value = "";
}
  
messageForm.addEventListener("submit", handleSubmit);
nickForm.addEventListener("submit", handleNickSubmit);

👉🏻각 폼들의 저장 버튼을 누르면 각 폼의 input 값을 server에 보내준다.

server.js
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}`)
          );
          break;
        case "nickname":
          socket["nickname"] = message.payload;
          break;
      }
    });
  });

👉🏻메시지를 받으면 먼저 json 형태로 파싱해준다. 그리고 메시지 타입에 따라 구별해 닉네임이면 socket["nickname"]에 저장하고 메시지면 브라우저로 보내준다.

💡소켓에 정보를 저장할 수 있다.

🐰성공! :)

728x90