Socket.io로 실시간 채팅 서비스 구현하기
Socket.io와 Node.js를 사용해 기본 실시간 채팅 서버와 클라이언트 구조, 이벤트 흐름, 배포·보안 고려사항을 초보자도 이해하기 쉽게 정리한 설명
목차
개요
실시간 채팅은 사용자 경험을 크게 향상시킨다. Socket.io는 WebSocket을 포함한 여러 전송 방식을 추상화해서 손쉽게 실시간 통신을 구현하게 한다. 이 글에서는 Socket.io 채팅 예제와 함께 Node.js 실시간 채팅 만들기 과정을 처음부터 단계별로 설명한다. 코드는 최소한의 구성으로 동작하도록 설계했다.
사전 준비
필수 환경
- Node.js (LTS 권장)
- npm 또는 yarn
- 기본적인 JavaScript 및 HTML 지식
패키지 설치
프로젝트 폴더에서 Express와 Socket.io를 설치한다. 이 단계가 Node.js 실시간 채팅 만들기의 첫걸음이다.
npm init -y
npm install express socket.io
서버 구현
간단한 Express + Socket.io 서버
아래 코드는 기본적인 서버 구조다. 클라이언트 연결, 메시지 수신, 브로드캐스트를 처리한다.
const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = new Server(server);
app.use(express.static('public'));
io.on('connection', (socket) => {
console.log('사용자 연결:', socket.id);
// 접속 이벤트
socket.on('join', (nick) => {
socket.nickname = nick || '익명';
socket.broadcast.emit('sys', `${socket.nickname}님이 입장했습니다.`);
});
// 메시지 수신
socket.on('message', (msg) => {
const payload = { from: socket.nickname || '익명', text: msg };
io.emit('message', payload);
});
// 접속 해제
socket.on('disconnect', () => {
io.emit('sys', `${socket.nickname || '사용자'}님이 퇴장했습니다.`);
});
});
server.listen(3000, () => console.log('서버 실행: http://localhost:3000'));
이 구조는 Socket.io 채팅 예제의 핵심 흐름을 보여준다. 서버는 클라이언트 이벤트를 받고, 필요하면 전체에 브로드캐스트한다.
클라이언트 구현
기본 HTML 및 클라이언트 스크립트
public/index.html 파일에 클라이언트 코드를 둔다. Socket.io 클라이언트 라이브러리는 서버에서 제공하는 스크립트를 사용한다.
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Socket.io 채팅 예제</title>
<style>
body{font-family:Arial;margin:16px}
#log{height:300px;border:1px solid #ccc;padding:8px;overflow:auto}
</style>
</head>
<body>
<h1>실시간 채팅</h1>
<div id="log"></div>
<input id="nick" placeholder="닉네임" />
<input id="msg" placeholder="메시지" />
<button id="send">전송</button>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();
const log = document.getElementById('log');
const nick = document.getElementById('nick');
const msg = document.getElementById('msg');
const send = document.getElementById('send');
function append(text){
const el = document.createElement('div');
el.textContent = text;
log.appendChild(el);
log.scrollTop = log.scrollHeight;
}
// 입장 알림 전송
send.addEventListener('click', () => {
if(!socket.connected) return;
socket.emit('join', nick.value);
socket.emit('message', msg.value);
msg.value = '';
});
// 서버 이벤트 처리
socket.on('message', (data) => append(`${data.from}: ${data.text}`));
socket.on('sys', (data) => append(`* ${data}`));
</script>
</body>
</html>
위 코드는 최소한의 채팅 인터페이스다. Socket.io 튜토리얼의 기본 개념인 연결, 이벤트 전송, 수신을 모두 포함한다.
이벤트 설계와 메시지 흐름
권장 이벤트 구조
- join: 닉네임이나 룸 정보 전달
- message: 사용자 메시지 전달
- sys: 시스템 알림 전달(입장/퇴장 등)
이벤트 이름을 간단명료하게 유지하면 확장 시 관리가 쉬워진다. 각 이벤트는 검증 로직을 거쳐 악의적 입력을 차단해야 한다.
실무 고려사항
스케일링
단일 프로세스는 소수의 연결에 적합하다. 다중 인스턴스 환경에서는 Socket.io 어댑터(예: Redis)를 사용해 이벤트를 공유해야 한다. 로드 밸런서 사용 시에는 세션 무결성을 위해 sticky session 또는 토큰 기반 인증을 고려한다.
보안
- HTTPS 적용으로 중간자 공격 방지
- 입력 값 검증으로 XSS·인젝션 차단
- 인증 토큰을 통해 허가된 사용자만 연결 허용
확장 아이디어
- 룸(채널) 기능 추가로 그룹 채팅 지원
- 메시지 영속화를 위한 데이터베이스 연동
- 읽음 표시, 타이핑 알림 등 UX 개선 기능
문제 해결 팁
- 연결 문제: 브라우저 콘솔과 서버 로그를 함께 확인
- 메시지 누락: 어댑터 설정과 네트워크 지연 검사
- 리소스 관리: 불필요한 이벤트 리스너 제거
정리
이 글은 Socket.io 채팅 예제 중심으로 Node.js 실시간 채팅 만들기 과정을 설명했다. 서버와 클라이언트의 핵심 코드, 이벤트 설계, 확장과 보안 고려사항을 포함한다. 처음 구현할 때는 단순 구조로 시작해 기능을 점진적으로 추가하는 방법이 안정적이다. 보다 큰 트래픽을 다루려면 Redis 어댑터, HTTPS, 인증 구조를 적용하는 것을 권장한다.