프로젝트 소개 및 목표
🔗 관련 에러 해결 가이드
실시간 채팅 앱 만들기 with Socket.io는 웹소켓 기반의 양방향 통신을 활용한 실전 프로젝트입니다. 이 프로젝트를 통해 실시간으로 메시지를 주고받는 채팅 애플리케이션을 구축하며, Node.js와 Socket.io의 핵심 개념을 익힐 수 있습니다. 완성된 앱은 여러 사용자가 동시에 접속하여 실시간으로 대화할 수 있으며, 사용자 입장/퇴장 알림, 타이핑 인디케이터 등의 기능을 포함합니다. 이 가이드를 따라하면 포트폴리오에 추가할 수 있는 완성도 높은 풀스택 프로젝트를 만들 수 있습니다.
필요한 기술 스택
이 프로젝트를 구현하기 위해서는 다음 기술들이 필요합니다:
- 백엔드: Node.js, Express.js, Socket.io
- 프론트엔드: HTML5, CSS3, JavaScript (Vanilla JS 또는 React)
- 개발 도구: npm 또는 yarn, VSCode
- 배포: Heroku, Render, 또는 Vercel
Node.js와 JavaScript의 기본 지식이 있으면 충분하며, Socket.io는 처음 접하더라도 이 가이드를 통해 쉽게 배울 수 있습니다.
프로젝트 셋업
먼저 프로젝트 디렉토리를 생성하고 필요한 패키지를 설치합니다:
mkdir realtime-chat-app
cd realtime-chat-app
npm init -y
npm install express socket.io
npm install --save-dev nodemon
프로젝트 구조를 다음과 같이 설정합니다:
realtime-chat-app/
├── server.js
├── public/
│ ├── index.html
│ ├── style.css
│ └── client.js
└── package.json
package.json의 scripts 섹션에 개발 서버 실행 명령어를 추가합니다:
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
}
단계별 구현 과정
1단계: Express 서버 설정
server.js 파일을 생성하고 기본 Express 서버를 구성합니다:
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require('socket.io');
const io = new Server(server);
const PORT = process.env.PORT || 3000;
// 정적 파일 제공
app.use(express.static('public'));
app.get('/', (req, res) => {
res.sendFile(__dirname + '/public/index.html');
});
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
2단계: Socket.io 연결 설정
서버에서 Socket.io 이벤트를 처리하는 로직을 추가합니다:
// 접속한 사용자 관리
const users = {};
io.on('connection', (socket) => {
console.log('새로운 사용자 접속:', socket.id);
// 사용자 입장
socket.on('join', (username) => {
users[socket.id] = username;
socket.broadcast.emit('user-connected', username);
io.emit('user-list', Object.values(users));
});
// 메시지 수신 및 전송
socket.on('chat-message', (data) => {
socket.broadcast.emit('chat-message', {
username: users[socket.id],
message: data.message,
timestamp: new Date().toISOString()
});
});
// 타이핑 상태
socket.on('typing', () => {
socket.broadcast.emit('typing', users[socket.id]);
});
socket.on('stop-typing', () => {
socket.broadcast.emit('stop-typing', users[socket.id]);
});
// 사용자 퇴장
socket.on('disconnect', () => {
const username = users[socket.id];
delete users[socket.id];
socket.broadcast.emit('user-disconnected', username);
io.emit('user-list', Object.values(users));
console.log('사용자 퇴장:', username);
});
});
3단계: 클라이언트 HTML 구성
public/index.html에 채팅 인터페이스를 작성합니다:
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>실시간 채팅 앱</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="chat-header">
<h1>실시간 채팅</h1>
<div id="user-count">접속자: 0명</div>
</div>
<div class="chat-body">
<div id="messages"></div>
<div id="typing-indicator"></div>
</div>
<form id="chat-form">
<input id="username-input" type="text" placeholder="이름을 입력하세요" required>
<input id="message-input" type="text" placeholder="메시지를 입력하세요" disabled>
<button type="submit">전송</button>
</form>
</div>
<script src="/socket.io/socket.io.js"></script>
<script src="client.js"></script>
</body>
</html>
4단계: 클라이언트 JavaScript 로직
public/client.js에 Socket.io 클라이언트 코드를 작성합니다:
const socket = io();
const chatForm = document.getElementById('chat-form');
const usernameInput = document.getElementById('username-input');
const messageInput = document.getElementById('message-input');
const messagesDiv = document.getElementById('messages');
const typingIndicator = document.getElementById('typing-indicator');
const userCount = document.getElementById('user-count');
let username = '';
let typingTimer;
// 사용자 입장 처리
usernameInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter' && usernameInput.value.trim()) {
e.preventDefault();
username = usernameInput.value.trim();
socket.emit('join', username);
usernameInput.style.display = 'none';
messageInput.disabled = false;
messageInput.focus();
addSystemMessage(`${username}님으로 입장했습니다.`);
}
});
// 메시지 전송
chatForm.addEventListener('submit', (e) => {
e.preventDefault();
const message = messageInput.value.trim();
if (message && username) {
socket.emit('chat-message', { message });
addMessage('나', message, true);
messageInput.value = '';
socket.emit('stop-typing');
}
});
// 타이핑 인디케이터
messageInput.addEventListener('input', () => {
if (!username) return;
socket.emit('typing');
clearTimeout(typingTimer);
typingTimer = setTimeout(() => {
socket.emit('stop-typing');
}, 1000);
});
// 메시지 수신
socket.on('chat-message', (data) => {
addMessage(data.username, data.message, false);
});
// 사용자 연결/해제
socket.on('user-connected', (username) => {
addSystemMessage(`${username}님이 입장했습니다.`);
});
socket.on('user-disconnected', (username) => {
addSystemMessage(`${username}님이 퇴장했습니다.`);
});
// 사용자 목록 업데이트
socket.on('user-list', (users) => {
userCount.textContent = `접속자: ${users.length}명`;
});
// 타이핑 상태
socket.on('typing', (username) => {
typingIndicator.textContent = `${username}님이 입력 중...`;
});
socket.on('stop-typing', () => {
typingIndicator.textContent = '';
});
// 메시지 추가 함수
function addMessage(sender, message, isOwn) {
const messageEl = document.createElement('div');
messageEl.className = `message ${isOwn ? 'own' : ''}`;
messageEl.innerHTML = `
<span class="sender">${sender}</span>
<span class="text">${message}</span>
<span class="time">${new Date().toLocaleTimeString()}</span>
`;
messagesDiv.appendChild(messageEl);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
function addSystemMessage(message) {
const messageEl = document.createElement('div');
messageEl.className = 'system-message';
messageEl.textContent = message;
messagesDiv.appendChild(messageEl);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
5단계: 스타일링
public/style.css로 깔끔한 UI를 구성합니다:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.container {
width: 90%;
max-width: 600px;
height: 80vh;
background: white;
border-radius: 10px;
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
display: flex;
flex-direction: column;
}
.chat-header {
background: #667eea;
color: white;
padding: 20px;
border-radius: 10px 10px 0 0;
display: flex;
justify-content: space-between;
align-items: center;
}
.chat-body {
flex: 1;
overflow-y: auto;
padding: 20px;
background: #f5f5f5;
}
#messages {
display: flex;
flex-direction: column;
gap: 10px;
}
.message {
display: flex;
flex-direction: column;
background: white;
padding: 10px;
border-radius: 8px;
max-width: 70%;
align-self: flex-start;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.message.own {
align-self: flex-end;
background: #667eea;
color: white;
}
.sender {
font-weight: bold;
font-size: 0.9em;
margin-bottom: 5px;
}
.time {
font-size: 0.7em;
opacity: 0.7;
margin-top: 5px;
}
.system-message {
text-align: center;
color: #888;
font-size: 0.9em;
margin: 10px 0;
}
#typing-indicator {
color: #667eea;
font-size: 0.9em;
margin-top: 10px;
min-height: 20px;
}
#chat-form {
display: flex;
padding: 20px;
background: white;
border-radius: 0 0 10px 10px;
}
input {
flex: 1;
padding: 12px;
border: 2px solid #ddd;
border-radius: 5px;
margin-right: 10px;
font-size: 14px;
}
input:focus {
outline: none;
border-color: #667eea;
}
button {
padding: 12px 24px;
background: #667eea;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-weight: bold;
}
button:hover {
background: #5568d3;
}
테스트 및 배포
로컬에서 애플리케이션을 실행하여 테스트합니다:
npm run dev
브라우저에서 http://localhost:3000을 열고, 여러 탭에서 동시에 접속하여 실시간 채팅 기능을 확인합니다. 배포는 Heroku나 Render를 추천합니다. Render 배포 예시:
git init
git add .
git commit -m "Initial commit"
git push origin main
Render 대시보드에서 새 Web Service를 생성하고 GitHub 저장소를 연결한 후, Build Command를 npm install, Start Command를 npm start로 설정합니다. 환경 변수로 PORT를 설정하면 자동으로 배포됩니다. WebSocket 지원이 필요하므로 Render의 기본 설정이면 충분합니다.
마무리 및 확장 아이디어
축하합니다! 실시간 채팅 앱 만들기 with Socket.io 프로젝트를 완성했습니다. 이제 다음과 같은 기능을 추가하여 프로젝트를 확장할 수 있습니다:
- 채팅방 분리 기능 (다중 룸)
- 사용자 프로필 이미지 및 커스터마이징
- 메시지 저장 및 히스토리 (MongoDB 연동)
- 파일 및 이미지 공유
- 이모지 및 리액션 기능
- JWT 인증을 통한 사용자 관리
- 음성/영상 통화 기능 (WebRTC)
이 프로젝트는 포트폴리오에 훌륭한 추가가 될 것이며, 실시간 통신 기술을 이해하는 데 큰 도움이 됩니다. GitHub에 코드를 올리고 라이브 데모 링크를 공유하여 더욱 완성도 높은 포트폴리오를 만들어보세요!
📚 함께 읽으면 좋은 글
실시간 채팅 앱 만들기 with Socket.io – 완성까지 한번에!
📅 2025. 11. 5.
🎯 실시간 채팅 앱 만들기 with Socket.io
실시간 채팅 앱 만들기 with Socket.io – 완성까지 한번에!
📅 2025. 11. 4.
🎯 실시간 채팅 앱 만들기 with Socket.io
실시간 채팅 앱 만들기 with Socket.io – 완성까지 한번에!
📅 2025. 10. 29.
🎯 실시간 채팅 앱 만들기 with Socket.io
실시간 채팅 앱 만들기 with Socket.io – 완성까지 한번에!
📅 2025. 10. 27.
🎯 실시간 채팅 앱 만들기 with Socket.io
실시간 채팅 앱 만들기 with Socket.io – 완성까지 한번에!
📅 2025. 10. 25.
🎯 실시간 채팅 앱 만들기 with Socket.io
💡 위 글들을 통해 더 깊이 있는 정보를 얻어보세요!
📢 이 글이 도움되셨나요? 공유해주세요!
여러분의 공유 한 번이 더 많은 사람들에게 도움이 됩니다 ✨
🔥 공유할 때마다 블로그 성장에 큰 힘이 됩니다! 감사합니다 🙏
💬 여러분의 소중한 의견을 들려주세요!
이 글을 읽고 새롭게 알게 된 정보가 있다면 공유해주세요!
⭐ 모든 댓글은 24시간 내에 답변드리며, 여러분의 의견이 다른 독자들에게 큰 도움이 됩니다!
🎯 건설적인 의견과 경험 공유를 환영합니다 ✨
🔔 블로그 구독하고 최신 글을 받아보세요!
🌟 프로젝트 아이디어부터 다양한 실생활 정보까지!
매일 새로운 유용한 콘텐츠를 만나보세요 ✨
📧 RSS 구독 | 🔖 북마크 추가 | 📱 모바일 앱 알림 설정
지금 구독하고 놓치는 정보 없이 업데이트 받아보세요!