Web

[WebSocket] 소켓으로 채팅 구현하기

전개발 2023. 7. 2. 04:35

개요

  • 기본적으로 HTTP 통신은 ,클라이언트 요청에 서버 응답 형태.
    • 서버는 수동적으로 응답만 하며, 능동적으로 클라이언트에 먼저 데이터를 전송할 수 없다.

Socket 통신은?

  • 클라이언트와 서버를 연결하고 실시간으로 통신이 가능하도록 하는 기술.
  • 별도의 요청없이 데이터를 주고받을 수 있다.
  • 채팅이나 주식보고서와 같은 곳에서 사용.
    • 교환 플랫폼, 게임 애플리케이션, 챗봇, 푸시알림, 소셜 네트워크, 채팅 애플리케이션 , IOT 애플리케이션 등
  • 해당 프로토콜은 정보를 동시에 송수신할 수 있어서 정보교환이 더 빨라짐.

연결 유지 시간

  • 서버나 클라이언트 둘 중 하나에 의해 종료되거나 시간초과에 의해 닫힐 때까지 열린상태로 유지됨.
  • 연결이 종료될 때까지 동일한 채널을 사용하여 통신이 수행됨.
  • 메시지는 양방향으로 교환됨.
  • 데이터를 암호화할 수 있음.

무엇을 만들까 ?!

양방향 통신 구현 (Chat 앱)

  • 채팅 기능 구현을 위해선, 서버에 접속된 모든 클라이언트들에게 메시지를 전송하는 기능이 필요.
  • 이를 브로드 캐스트 라고함.
  • 서버 접속 및 연결 해제 정보와 접속한 사용자 이름, 메시지를 모든 클라이언트에게 전송하는 간단한 채팅기능을 구현.

기능 상세

서버에 새로운 유저 접속하거나 연결 해제시, 접속된 모든 클라이언트 유저에게 접속 및 해제 사실과 현재 접속된 전체 유저수를 알린다.(브로드캐스트 한다)

  • 유저 접속시 : “새로운 유저 접속 [ 현재 : X 명 ]
  • 유저 퇴장시 : “유저 연결 해제 [ 현재 : X 명]
  • 채팅 입력 시 닉네임과 메시지를 출력. (모든 클라이언트에게 브로드 캐스트)

Server 및 Client 구현 과정

  • 웹 소켓 통신을 주고받을 서버와 클라이언트가 필요.
  • 실습에서는 Node.js 의 express.js 프레임워크를 사용.

[Server] Node.js의 express.js 프레임워크를 사용해 서버 구축

서버 구축 프레임워크 (express) 설치

> project directory
npm init
npm i express

/에 index.js 작성하기

const express = require("express");
const app = express();

app.use(express.static("front"));

app.listen(8000, () => {
  console.timeLog(`Server Listening on port 8000`);
});

/에서 node index.js 명령어를 실행 후, 크롬에서 localhost:8000 접속 후 서버 테스트

[Server] ws 웹 소켓 라이브러리를 사용해 간단한 WebSocket 통신 구현

/에서 npm i ws

index.js에서 ws 모듈 불러와 8001번을 통해 접속하는 코드 추가

const express = require("express");
const { WebSocketServer } = require("ws");
const app = express();

app.use(express.static("front"));

app.listen(8000, () => {
  console.timeLog(`Server Listening on port 8000`);
});

const wss = new WebSocketServer({ port: 8001 });

wss.on("connection", (ws) => {
  ws.on("message", (data) => {
    console.log(`Received fron client : ${data}`);
  });
});

[Client] /에 front라는 폴더 만들고, index.html 작성하기

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Web Socket 실습</title>
</head>
<body>
    <h1>Web Socket 실습 과제</h1>
</body>
</html>

[Client] 클라이언트(index.html)에서, 버튼을 만들고, 버튼 클릭 시 ‘hello’메시지를 웹소켓을 통해 서버로 보내는 코드 추가

  • 이때, WebSocket 생성자가 자바스크립트에 내장되어 있기 때문에 이를 사용해 구현.
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Web Socket 실습</title>
    <script>
      const ws = new WebSocket("ws://localhost:8001")

      function sendMsg() {
          ws.send("Hello");
      }
    </script>
  </head>
  <body>
    <h1>Web Socket 실습 과제</h1>
    <button onclick="sendMsg()">전송</button>
  </body>
</html>

서버 재실행 후, 클라이언트에서 전송 버튼을 누르면 8001번 포트를 향해 메시지를 보내고, 이를 서버에서 수신.


최종 코드

- https://hudi.blog/websocket-with-nodejs/ 블로그 게시글 참고

// 클라이언트

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Web Socket 실습</title>
    <script>
      const ws = new WebSocket("ws://localhost:8001")

      // 메시지 서버로 전달
      function sendMsg() {
        const nickname = document.getElementById("nickname")
        const message = document.getElementById("message")
          ws.send(`${nickname.value} : ${message.value}`);
          message.value = ""
      }

      // 수신한 메시지를 dom에 추가.
      function receiveMessage(event) {
        const chat = document.createElement("div");
        const message = document.createTextNode(event.data);
        chat.appendChild(message);

        const chatArea = document.getElementById("chat-area");
        chatArea.appendChild(chat)
      }

      // 메시지 수신 시 receiveMessage 함수 실행.
      ws.onmessage = receiveMessage;
    </script>
  </head>
  <body>
    <h1>SaSao Talk</h1>
    <div
      id="chat-area"
      style="width : 670px; height: 500px; background-color:lightgray; overflow-y: scroll;"
    ></div>
    <div style="margin-top:10px;">
      <input
        id="nickname"
        placeholder="닉네임"
        style="width: 100px;  height:30px"
      />
      <input
        id="message"
        placeholder="메시지를 입력하세요."
        style="width: 500px; height:30px"
      />
      <button style="line-height:30px" onclick="sendMsg()">전송</button>
    </div>
  </body>
</html>

// 서버

const express = require("express");
const { WebSocketServer } = require("ws");
const app = express();

app.use(express.static("front"));

app.listen(8000, () => {
  console.log(`Server Listening on port 8000`);
});

const wss = new WebSocketServer({ port: 8001 });

// 클라이언트 연결시
wss.on("connection", (ws, req) => {
  // 신규 유저 접속 시, 접속 정보 브로드 캐스트
  wss.clients.forEach((client) => {
    client.send(`새로운 유저 접속 [ 현재 : ${wss.clients.size}명 ]`);
  });
  console.log(`새로운 유저 접속 : ${req.socket.remoteAddress}`);

  // 클라이언트로부터 메시지 수신하면, 해당 메시지 브로드캐스트
  ws.on("message", (data) => {
    console.log(`${data}`);
    wss.clients.forEach((client) => {
      client.send(`${data}`);
    });
  });

  // 유저 연결 해제 시, 접속 정보 브로드 캐스트
  ws.on("close", () => {
    wss.clients.forEach((client) => {
      client.send(`유저 연결 해제 [ 현재 : ${wss.clients.size}명 ]`);
    });
  });
});

구현 결과

https://youtu.be/EuEm9nbcu-A

느낀 점

  • 주요 기술 중 하나인 Web Socket을 간단하게 이해할 수 있었습니다.
  • 프로젝트들에서 많이 쓰일, 채팅 구현의 핵심이 되는 기술이기 때문에 꼭 알아두어야 겠다고 생각했습니다 !!