Nodejs

[Node.js] Socket.IO를 사용한 웹 채팅 만들기

teamnova 2025. 2. 24. 21:39
728x90

이번에는 Socket.IO를 사용한 간단한 채팅을 만들어 보겠습니다.

Socket.IO를 사용하면 웹소켓을 쉽게 구현이 가능합니다. 클라이언트와 서버간의 통신이 가능합니다.

 

  • 왜 이 코드를 사용할까?
    • 실시간 채팅 구현이 간편함 → Socket.IO를 사용하면 복잡한 웹소켓 프로토콜을 신경 쓰지 않고도 채팅 기능을 쉽게 구축할 수 있음.
    • 빠른 데이터 전송 가능 → 서버와 클라이언트가 이벤트 기반으로 데이터를 주고받음 -> 채팅이 가능.
    • Node.js의 비동기 처리 → 대량의 동시 접속자를 처리하기에 적합.
  • 어디에 활용하면 좋을까?
    • 기본적인 채팅 애플리케이션 → 익명 채팅, 고객 문의 챗봇, 커뮤니티 채팅 등에 활용 가능.
    • 실시간 알림 시스템 → 사용자에게 실시간 알림을 보내는 기능에 응용 가능.
    • 멀티 유저 협업 도구 → 실시간 공동 편집, 화상 회의 채팅 기능 등에 적용 가능.

 

터미널에서 초기화 및 필요한 패키지 설치

 

npm init -y npm
install express socket.io

 

 

index.html

<!-- HTML5 문서임을 선언. 최신 표준으로 브라우저가 인식 -->
<!DOCTYPE html>
<!-- HTML 문서의 시작. lang 속성은 생략했지만 기본적으로 영어로 간주 -->
<html>
<head>
  <!-- 페이지 제목. 브라우저 탭에 표시 -->
  <title>실시간 채팅</title>
  <!-- CSS 스타일을 정의. 페이지 모양 꾸밈 -->
  <style>
    /* body 요소의 글꼴을 Arial로 설정.  */
    body { font-family: Arial, sans-serif; }
    /* 메시지 목록의 스타일. 기본 목록 점을 없애고 여백을 조정 */
    #messages { list-style-type: none; padding: 0; }
    /* 각 메시지 항목에 여백을 줘서 보기 좋게함함 */
    #messages li { padding: 5px; }
  </style>
</head>
<body>
  <!-- 메시지가 표시될 unordered list. 채팅 내용을 담는 공간 -->
  <ul id="messages"></ul>
  <!-- 메시지 입력 폼. 사용자가 텍스트를 입력하고 전송 -->
  <form id="form" action="">
    <!-- 텍스트 입력 필드. autocomplete 끄고, ID로 쉽게 접근 가능 -->
    <input id="input" autocomplete="off" />
    <!-- 전송 버튼. 클릭하면 폼이 제출출 -->
    <button>전송</button>
  </form>

  <!-- Socket.IO 클라이언트 스크립트를 서버에서 가져옴. 실시간 통신의 핵심 -->
  <script src="/socket.io/socket.io.js"></script>
  <!-- 클라이언트 측 JavaScript 코드 시작 -->
  <script>
    // 사용자에게 이름 입력창을 띄우고 입력값을 저장. 채팅에서 사용할 닉네임
    const username = prompt('채팅에서 사용할 이름을 입력하세요:');
    // Socket.IO로 서버와 연결 시작. 실시간 통신을 위한 소켓 객체를 만듬듬
    const socket = io();

    // 서버에 'user joined' 이벤트를 보내 유저 이름을 전달. 입장 처리 시작
    socket.emit('user joined', username);

    // HTML에서 form 요소를 가져옴. 메시지 전송을 처리
    const form = document.getElementById('form');
    // 입력 필드를 가져옴. 사용자가 메시지를 입력하는 곳
    const input = document.getElementById('input');
    // 메시지 목록을 가져옴. 새 메시지를 여기 추가
    const messages = document.getElementById('messages');

    // 폼 제출 이벤트 리스너 추가. 메시지를 보내는 트리거
    form.addEventListener('submit', (e) => {
      // 기본 폼 제출 동작(페이지 새로고침)을 막음. 실시간 앱에선 필요 없음
      e.preventDefault();
      // 입력값이 비어있지 않으면 실행
      if (input.value) {
        // 서버에 'chat message' 이벤트로 이름과 메시지를 보냄
        socket.emit('chat message', { username, message: input.value });
        // 입력 필드를 비움. 다음 메시지를 위해 준비
        input.value = '';
      }
    });

    // 서버에서 'chat message' 이벤트를 받으면 실행. 새 메시지를 표시
    socket.on('chat message', (data) => {
      // 새로운 li 요소를 만듦. 메시지를 담을 공간
      const li = document.createElement('li');
      // 메시지 형식으로 텍스트 설정. "이름: 메시지" 형태
      li.textContent = `${data.username}: ${data.message}`;
      // 메시지 목록에 새 li를 추가. 채팅창에 메시지 나타남
      messages.appendChild(li);
    });
  </script>
</body>
</html>

 

server.js

// Express 모듈을 가져옴. 웹 서버를 쉽게 만들 수 있게 도와주는 프레임워크.
const express = require('express');
// Node.js 기본 모듈인 http를 가져옴. 웹 서버를 직접 만들 때 필요요.
const http = require('http');
// Socket.IO 모듈에서 Server 클래스를 가져옴. 실시간 통신을 위해 사용.
const { Server } = require('socket.io');
// 경로 처리를 쉽게 해주는 Node.js 기본 모듈.
const path = require('path');

// Express 앱을 생성. 이걸로 웹 요청을 처리.
const app = express();
// Express 앱을 기반으로 HTTP 서버를 만듦. Socket.IO가 이 서버 위에서 동작.
const server = http.createServer(app);
// Socket.IO 서버를 만듦. 실시간 양방향 통신을 가능.
const io = new Server(server);

// 서버가 사용할 포트 번호를 3000으로 설정. 브라우저에서 접속할 때 이 번호를 사용.
const port = 3000;

// '/' 경로로 GET 요청이 오면 index.html 파일을 클라이언트에게 보냄. 채팅 UI를 보여주는 기본 페이지.
app.get('/', (req, res) => {
  // __dirname은 현재 파일의 경로를 뜻하고, path.join으로 index.html 파일 경로를 안전하게.
  res.sendFile(path.join(__dirname, 'index.html'));
});

// 클라이언트가 소켓으로 연결되면 이 코드가 실행.
io.on('connection', (socket) => {
  // 새로운 사용자가 접속했음을 서버 콘솔에 출력. 디버깅이나 상태 확인.
  console.log('새로운 사용자가 연결되었습니다!');

  // 클라이언트가 'user joined' 이벤트를 보내면 실행. 유저 이름을 받아 처리.
  socket.on('user joined', (username) => {
    // 현재 소켓에 유저 이름을 저장. 나중에 퇴장할 때 사용용.
    socket.username = username;
    // 서버 콘솔에 누가 입장했는지 출력. 어떤 유저가 들어왔는지 확.
    console.log(`${username}님이 입장했습니다!`);
    // 모든 클라이언트에게 시스템 메시지로 입장 알림을 보냄. 채팅창에 표시.
    io.emit('chat message', { username: '시스템', message: `${username}님이 입장했습니다!` });
  });

  // 클라이언트가 'chat message' 이벤트를 보내면 실행. 채팅 메시지를 받아 처리.
  socket.on('chat message', (data) => {
    // 서버 콘솔에 누가 어떤 메시지를 보냈는지 출력. 로그로 남겨서 확인 가능.
    console.log(`${data.username}: ${data.message}`);
    // 모든 클라이언트에게 받은 메시지를 그대로 전달. 실시간 채팅이 가능.
    io.emit('chat message', { username: data.username, message: data.message });
  });

  // 클라이언트가 연결을 끊으면 실행. 접속 종료를 감지.
  socket.on('disconnect', () => {
    // 서버 콘솔에 누가 나갔는지 출력. username이 없으면 '익명'으로 표시.
    console.log(`${socket.username || '익명'}님이 연결을 끊었습니다.`);
    // 모든 클라이언트에게 시스템 메시지로 퇴장 알림을 보냄. 채팅창에 표시.
    io.emit('chat message', { username: '시스템', message: `${socket.username || '익명'}님이 퇴장했습니다!` });
  });
});

// 서버를 포트 3000에서 실행 시작. 성공하면 콘솔에 메시지를 띄움.
server.listen(port, () => {
  // 서버가 잘 시작됐는지 확인하기 위해 콘솔에 출력. URL도 알림림.
  console.log(`서버가 http://localhost:${port}에서 실행 중입니다!`);
});

 

터미널에서 node server.js 입력 후 실행

 

시연영상