카테고리 없음

예반씨의 WebSocket 간단히 경험하기

yebeen 2024. 7. 14. 23:48

 

✨WebSocket이란?

웹 애플리케이션에서 클라이언트와 서버 간의 상호작용을 실시간으로 처리할 수 있게 해주는 통신 프로토콜
기존의 HTTP와 비교할 때, WebSocket은 양방향 통신을 지원하고, 더 낮은 지연시간으로 데이터를 주고받을 수 있어
실시간 데이터 전송에 매우 적합합니다.
 
 
 

✨WebSocket vs HTTP

통신방식

HTTP

  • 요청-응답 모델 
  • HTTP는 클라이언트가 서버에 요청을 보내고, 서버가 이에 대한 응답을 보내는 요청-응답 모델을 따른다.
  • 각 요청마다 새로운 연결을 맺고 끊기 때문에, 많은 요청을 처리할 때 오버헤드가 발생할 수 있다.
  • 단방향 통신
  • 클라이언트가 요청을 보내기 전까지는 서버가 클라이언트에 데이터를 보낼 수 없다.
  • 즉, 서버에서 클라이언트로의 데이터 전송이 제한적이다.

WebSocket

  • 양방향 통신
  • WebSocket은 클라이언트와 서버가 양방향으로 데이터를 주고받을 수 있는 지속적인 연결을 제공한다.
  • 초기 핸드셰이크 과정 이후, 동일한 연결을 통해 양방향 통신이 가능하다.
  • 지속적 연결
  • 연결이 되면 클라이언트와 서버는 지속적으로 데이터를 주고받을 수 있고 HTTP와 달리 매번 새로운 연결을 설정하지 않아도 된다.

 
 

성능과 효율성

HTTP

  • 높은 오버헤드
  • 매 요청마다 새로운 TCP 연결을 설정하고 끊는 과정에서 오버헤드가 발생한다.
    특히, 실시간 데이터 전송이 필요한 애플리케이션에서는 비효율적!!!
  • 헤더 데이터
  • 각 요청마다 HTTP 헤더를 포함하여 데이터를 전송하기 때문에, 작은 데이터 전송에도 불필요한 정보가 추가된다.

WebSocket

  • 낮은 오버헤드
    초기 연결 설정 이후에는 지속적으로 데이터를 주고받을 수 있기 때문에, 연결 설정에 대한 오버헤드가 줄어든다.
  • 헤더 최소화
    핸드셰이크 이후에는 데이터 프레임의 헤더가 최소화되어 있어, 데이터 전송의 효율성이 높다.


사용하는 곳

HTTP

정적 콘텐츠을 제공하거나  요청-응답 기반의 데이터 전송이 주로 필요할 때 사용한다.
클라이언트가 서버에 요청을 보내고, 서버가 응답하는 구조로 설계된 애플리케이션에서 사용한다. = RESTful API
 

WebSocket
채팅, 게임, 라이브 등 실시간 데이터 전송이 필요한 애플리케이션에서 사용된다.
실시간 알림의 경우 서버에서 클라이언트로 실시간 알림을 전송해야하기에 사용된다.

 
 
 
 

✨WebSocket을 이용한 서버와 통신 [ feat. NodeJs ]

 

시작하기 전 해야할 설정

  1. folder 생성 후 vsc코드로 해당 폴더를 열기
  2.  npm init -y
  3.  npm i nodemon -D 
  4. babel.config.json 생성 후 다음과 같은 내용 추가
    { "presets": ["@babel/preset-env"] }
  5. src 생성하기 + server.js만들기
  6. git init . 후 bable설치
    npm i @babel/core -D npm i @babel/cli -D npm i @babel/node -D
  7. nodemon.json 생성 후 추가 
  8. { "ignore":["src/public/*"], //서버가 바뀔때만 새로고침하도록 함 "exec" : "babel-node src/server.js" //server.js에 대해 babel-node 명령문 실행 }
  9. npm i @babel/preset-env -D 실행
  10. package.json에 "scripts":{ "dev": "nodemon" } 추가
  11. npm i express 
  12. npm i pug
  13. 다음과 같은 구조를 가지도록 public/js/app.js, views/home.pug 생성하기

 
 
 

핵심코드

<!-- home.pug -->
doctype html
html(lang="en")
    head
        meta(charset="UTF-8")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        title Zoome Clone
        link(rel="stylesheet" href="https://unpkg.com/mvp.css")
    body 
        script(src="../public/js/app.js")

 
 

//server.js
import http from "http";
import WebSocket from "ws";
import express from "express";
const app = express();
const PORT = 3000;
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(`Server Listening...: : http://localhost:${PORT}`)
}

//서버 생성
const server = http.createServer(app);
const wss = new WebSocket.Server({server});

//연결하기
wss.on("connection",(socket)=>{
    console.log("Connected To Browser");
    //socket에서 제공하는 메서드로 wss아님
    
    //연결이 끊겼을 때
    socket.on("close",()=>{console.log("Disconnected To Browser");});
    
    //브라우저로부터 메세지가 왔을 때
    socket.on("message",(message)=>{
        console.log(message.toString('utf8'));
    })
    
    //브라우저로 메세지 보내기
    socket.send("Hello~"); // -> message event
    
});


server.listen(3000,handleListen);

 
 

//app.js

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

 
 

실행결과