9_yoon
개발저장소
9_yoon
전체 방문자
오늘
어제
  • 분류 전체보기 (101)
    • 알고리즘 (52)
      • BJ (40)
      • 프로그래머스 (0)
      • SWEA (10)
      • JO (2)
    • 이론 공부 (7)
      • 네트워크 (2)
      • 알고리즘 (2)
      • Java (1)
      • Web (1)
      • 기타 (1)
    • 개발 공부 (35)
      • Project (1)
      • JavaScript (1)
      • Typescript (1)
      • Spring (12)
      • Java (2)
      • Next JS (7)
      • React (3)
      • Vue (1)
      • Web (5)
      • 기타 (2)
    • 기타 (7)
      • SSAFY (7)
      • 일상 (0)

인기 글

태그

  • 김영한 스프링
  • 노마드코더
  • SWEA
  • React
  • 백준
  • 스프링
  • NextJS
  • 싸피7기
  • SSAFY
  • 싸피

최근 글

티스토리

hELLO · Designed By 정상우.
9_yoon

개발저장소

[Web] WebSocket 정리
개발 공부/Web

[Web] WebSocket 정리

2022. 7. 26. 10:29
728x90
반응형

https://nomadcoders.co/noom/lobby

 

줌 클론코딩 – 노마드 코더 Nomad Coders

WebSockets, SocketIO, WebRTC

nomadcoders.co

노마드코더의 줌 클론코딩 강의를 보고 정리한 내용입니다. 

 

HTTP

http는 모든 서버들이 작동하는 방식

유저가 req를 보내면 서버가 res로 반응한다. 

http에서 기억해야할 중요한 것은 stateless, 즉 백엔드가 유저를 기억하지 못한다. 유저와 백엔드 사이에 연결이 없다.

서버는 오직 req을 받을 때만 답장을 해준다.

 

Websocket

webSocket을 사용해서 연결하고 싶고, 서버가 지원한다면 wss(secure web socket)으로 접속하면 된다.

ex)  https://nomadcoders.co => wws://nomadcoders.co 

 

과정

브라우저가 서버로 webSocket request를 보내면 서버가 받거나 거절한다. 수락하면 연결이 성립된다.

연결되어있기 때문에 서버는 사용자가 누구인지 기억할 수 있다. 그리고 요청이 없어도 유저에게 메시지를 보낼 수 있다. 

유저는 언제든지 서버에 메시지를 보낼 수 있고, 서버도 언제든지 유저에게 메시지를 보낼 수 있다.

bi-directional 연결이 성립하고, webSocket은 브라우저 -백엔드간, 백엔드-백엔드 간에 연결에서 사용된다.

 

클라이언트 측

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

//socket : 서버로의 연결
const socket = new WebSocket(`ws://${window.location.host}`);

//서버와 연결
socket.addEventListener("open", () => {
  console.log("Connected to Server ✅");
});

//메시지
socket.addEventListener("message", (message) => {
  console.log("New message : ", message.data, "from the Server");
});

//서버 연결 종료
socket.addEventListener("close", () => {
  console.log("Disconnected from Server ❌");
});

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

function handleSumbit(event) {
  event.preventDefault();
  const input = messageForm.querySelector("input");
  socket.send(input.value);
  input.value = "";
}

messageForm.addEventListener("submit", handleSumbit);

 

서버측

import express from "express";
import http from "http";
import WebSocket from "ws";

const app = express();

app.set("view engine", "pug");
app.set("views", __dirname + "/views");
app.use("/public", express.static(__dirname + "/public"));
app.get("/", (req, res) => res.render("home"));
//어떤 경로를 들어와도 항상 /로 리다이렉트
app.get("/*", (req, res) => res.redirect("/"));

const handleListen = () => console.log("Listening ong http://localhost:3000");

const server = http.createServer(app); //http 서버
// http서버 위에 wss만들기
const wss = new WebSocket.Server({ server }); //webSocket 서버 + http 서버를 합쳐서 하나의 포트를 사용하기 위해서

wss.on("connection", (socket) => {
  //socket : 연결된 브라우저
  console.log("Connected to browser ✅");
  console.log(socket);
  //브라우저와 연결 종료
  socket.on("close", () => {
    console.log("Disconnected from the Browser ❌");
  });

  //브라우저에서 메세지 받기
  socket.on("message", (message) => {
    socket.send(message.toString());
  });

  //브라우저에 메시지 보내기
  // socket.send("hello");
});

server.listen(3000, handleListen);

 

그러나 위의 코드는 다른 사람들과의 소통은 안되고 클라이언트와 서버와의 소통만 가능한 상태이다. 

예를 들어 크롬에서 접속하고, 파이어폭스에서 접속을 한 상태에서 크롬에서 메시지를 보내도 파이어폭스에게는 해당 메시지를 전달이 안된다. 

각각 다른 브라우저와 소통을 하기 위해서 브라우저와 서버가 연결 됐을때 소켓 배열에서 해당 소켓을 추가해준다. 

const sockets = [];

wss.on("connection", (socket) => {
  //socket : 연결된 브라우저

  //연결된 브라우저들을 sockets 배열에 넣어주기
  sockets.push(socket);
}

그리고 서버에서 메시지를 받으면 해당 메시지을 sockets에 있는 다른 브라우저에게 보내준다.

//브라우저에서 메세지 받기
socket.on("message", (message) => {
sockets.forEach((aSocket) => aSocket.send(message.toString()));
});

 

그리고 브라우저에서는 메시지를 받으면 콘솔이 아닌 li태그로 보여주도록 수정해준다.

//메시지 받기
socket.addEventListener("message", (message) => {
  const li = document.createElement("li");
  li.innerText = message.data;
  messageList.append(li);
});

 

닉네임 설정

닉네임을 설정해주도록 해보자

메시지가 올 때 닉네임, 메시지 등의 종류를 구별해주기 위해서 타입을 구별해야한다. 그러기 위해서 string으로 보냈던 메시지를 json으로 보내보도록 하자

 

메시지의 타입과 내용을 서버에게 json으로 보내기

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

json객체로 변환하는 함수 선언해주고

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));
}

다음과 같이 서버에게 메시지를 전송할 때는 위에서 만들었던 함수를 사용해서 json 객체로 보내준다.

이상태에서 서버에 메시지를 받을 때 콘솔을 출력해보면

다음과 같은 형태의 스트링으로 출력이 된다. 그래서 이걸 JSON객체로 변환 후 사용해주도록 한다.

 //브라우저에서 메세지 받기
  socket.on("message", (message) => {
    const parsed = JSON.parse(message);
    console.log(parsed);
    console.log(message.toString());
    sockets.forEach((aSocket) => aSocket.send(message.toString()));
  });

json으로 받을 때와 string으로 받을 때

 

서버에서는 메시지 type에 따라서 다른 처리를 해준다.

//브라우저에서 메세지 받기
  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을 추가
        socket["nickname"] = message.payload;
    }
  });

타입이 "new_message"인 경우에는 다른 소켓들에게 닉네임과 같이 메시지를 보내주고,

"nickname"인 경우에는 socket에 nickname을 설정해준다.

728x90
반응형
저작자표시 비영리 동일조건 (새창열림)

'개발 공부 > Web' 카테고리의 다른 글

[Web] WebRTC  (0) 2022.07.29
[Web]SocketIO  (0) 2022.07.27
라디오 버튼을 이미지로 구현하기 [이전 블로그 게시글]  (0) 2022.02.16
[정리] 웹 폰트란? [이전 블로그 게시글]  (0) 2022.02.16
    '개발 공부/Web' 카테고리의 다른 글
    • [Web] WebRTC
    • [Web]SocketIO
    • 라디오 버튼을 이미지로 구현하기 [이전 블로그 게시글]
    • [정리] 웹 폰트란? [이전 블로그 게시글]
    9_yoon
    9_yoon
    배울게 넘쳐나는 개발 세상에서 묵묵히 걸어가며 지식을 쌓는 신입 개발자

    티스토리툴바