본문 바로가기
IT & Tech 정보

🚀 WebSocket 기반 실시간 채팅 서버: Socket.IO + React

by 지식과 지혜의 나무 2025. 5. 25.
반응형


이번에는 Socket.IO와 React를 이용해 실시간 채팅 애플리케이션을 만드는 방법을 단계별로 살펴보겠습니다.
서버-클라이언트 간 메시지 전송, 방(Room) 관리, 사용자 연결·해제 처리 등을 코드 스니펫과 함께 제공합니다.



📋 목차
1. WebSocket vs HTTP
2. 프로젝트 초기 설정
3. 서버: Node.js + Socket.IO
4. 클라이언트: React + socket.io-client
5. 채팅방 관리 & 이벤트 핸들러
6. 인증·CORS 설정
7. 배포 시 고려사항
8. 마무리



1️⃣ WebSocket vs HTTP
• HTTP: 요청(Request)→응답(Response) 구조, 서버 푸시 불가
• WebSocket: 클라이언트↔서버 간 지속 연결, 양방향 실시간 통신 지원
• Socket.IO: WebSocket 위에서 자동 재연결·룸·네임스페이스 기능 제공



2️⃣ 프로젝트 초기 설정

# 1) 서버 폴더 생성 및 패키지 설치
mkdir realtime-chat && cd realtime-chat
npm init -y
npm install express socket.io cors

# 2) 클라이언트용 React 앱 생성
npx create-react-app client --template typescript
cd client
npm install socket.io-client

• 서버는 realtime-chat/에, React 클라이언트는 realtime-chat/client/에 위치



3️⃣ 서버: Node.js + Socket.IO

// index.js (서버 루트)
const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const cors = require('cors');

const app = express();
app.use(cors());

const server = http.createServer(app);
const io = new Server(server, {
  cors: { origin: '*' }
});

// 클라이언트 연결 시
io.on('connection', socket => {
  console.log(`유저 연결됨: ${socket.id}`);

  // 채팅방 참가
  socket.on('joinRoom', room => {
    socket.join(room);
    socket.to(room).emit('systemMessage', `${socket.id} 님이 입장했습니다.`);
  });

  // 메시지 수신 및 브로드캐스트
  socket.on('chatMessage', ({ room, user, message }) => {
    io.to(room).emit('chatMessage', { user, message, timestamp: Date.now() });
  });

  // 채팅방 나가기
  socket.on('leaveRoom', room => {
    socket.leave(room);
    socket.to(room).emit('systemMessage', `${socket.id} 님이 퇴장했습니다.`);
  });

  // 연결 해제 시
  socket.on('disconnect', () => {
    console.log(`유저 연결 해제: ${socket.id}`);
  });
});

const PORT = process.env.PORT || 4000;
server.listen(PORT, () => console.log(`서버 실행 중: http://localhost:${PORT}`));

• socket.join(room) / socket.leave(room) 로 방 관리
• io.to(room).emit(...) 으로 특정 방에 메시지 전송



4️⃣ 클라이언트: React + socket.io-client

// client/src/App.tsx
import React, { useState, useEffect } from 'react';
import io, { Socket } from 'socket.io-client';

let socket: Socket;

function App() {
  const [room, setRoom] = useState('general');
  const [user, setUser] = useState('');
  const [message, setMessage] = useState('');
  const [chat, setChat] = useState<{user:string;message:string;timestamp:number}[]>([]);

  useEffect(() => {
    socket = io('http://localhost:4000');
    socket.emit('joinRoom', room);

    socket.on('chatMessage', data => {
      setChat(prev => [...prev, data]);
    });
    socket.on('systemMessage', msg => {
      setChat(prev => [...prev, { user: 'System', message: msg, timestamp: Date.now() }]);
    });

    return () => { socket.disconnect(); };
  }, [room]);

  const sendMessage = () => {
    if (message.trim()) {
      socket.emit('chatMessage', { room, user, message });
      setMessage('');
    }
  };

  return (
    <div>
      <h1>실시간 채팅 ({room} 방)</h1>
      <input placeholder="닉네임" value={user} onChange={e => setUser(e.target.value)} />
      <div style={{ border:'1px solid #ccc', height:300, overflowY:'scroll' }}>
        {chat.map((c, i) => (
          <p key={i}><strong>{c.user}:</strong> {c.message}</p>
        ))}
      </div>
      <input
        placeholder="메시지 입력"
        value={message}
        onChange={e => setMessage(e.target.value)}
        onKeyPress={e => e.key === 'Enter' && sendMessage()}
      />
      <button onClick={sendMessage}>전송</button>
    </div>
  );
}

export default App;

• io('http://localhost:4000') 로 서버에 연결
• 메시지 수신 시 socket.on 핸들러에서 상태 업데이트



5️⃣ 채팅방 관리 & 이벤트 핸들러
• joinRoom: 사용자가 특정 방에 입장
• leaveRoom: 방 퇴장 시 시스템 메시지 전송
• chatMessage: { room, user, message } 형식으로 브로드캐스트
• systemMessage: 서버 측 상태 메시지를 별도 이벤트로 전달



6️⃣ 인증·CORS 설정
• JWT 인증
• 클라이언트가 연결 시 socket.auth = { token } 설정
• 서버에서 io.use((socket, next) => jwt.verify(...)) 로 검증
• CORS

const io = new Server(server, {
  cors: {
    origin: ['https://your-domain.com'],
    methods: ['GET','POST'],
    credentials: true
  }
});





7️⃣ 배포 시 고려사항
• 스케일링: 여러 노드에 분산 배포 시 Redis 어댑터 (socket.io-redis) 사용
• 로드 밸런서: sticky session 또는 클러스터링 필요
• SSL/TLS: https 서버에서 Socket.IO 연결
• 환경 변수: 서버 URL·포트·JWT 비밀키 분리



8️⃣ 마무리

Socket.IO와 React를 조합해 실시간 양방향 통신을 구현하는 과정을 살펴봤습니다.
채팅방, 시스템 메시지, 인증, 확장성까지 기본 구조를 익혔으니,
여러분만의 기능(파일 전송, 이모티콘, 1:1 채팅 등)을 추가해 보세요!

반응형