1. 시그널링 서버
WebRTC에서 P2P 연결을 설정하기 위한 초기 정보 교환을 중계하는 서버입니다. WebRTC는 브라우저 간 직접 통신을 지원하지만, 이 연결을 설정하기 위해서 초기 메타데이터 교환을 위한 시그널링 서버가 필요합니다.
주요 역활
- 세션 정보(SDP) 교환: 오디오, 비디오, 네트워크 설정 등의 정보
- ICE 후보(candidate) 교환: 네트워크 연결 정보
- 사용자 발견 및 세션 관리: 사용자 ID 할당, 방(room) 생성 및 관리
- 상태 동기화: 연결 상태, 참여자 목록 등의 정보 공유
2. Socket.IO
웹소켓 기반의 실시간 양방향 통신 라이브러리로, 시그널링 서버를 구현하기에 최적화되어 있습니다.
주요 기능
- 신뢰성 있는 연결: 웹소켓 연결이 불가능할 경우 롱폴링, AJAX 등 대체 방식으로 자동 전환
- 방(Room) 관리: 효율적인 그룹 통신 지원 및 멀티캐스트 기능
- 이벤트 기반 통신: 명확한 이벤트 이름으로 메시지 타입 구분
- 자동 재연결: 네트워크 불안정 시 자동 재연결 처리
- 바이너리 데이터 지원: 이미지, 오디오 등의 바이너리 데이터 전송 지원
3. MongoDB 어댑터
NoSQL 형식의 데이터베이스인 MongoDB 어댑터를 활용하여 시그널링 서버(Socket.IO)에 연결하여 사용 가능합니다.
Socket.IO와 NoSQL 형식의 데이터베이스인 MongoDB 를 연결하여 상태 관리와 데이터 지속성을 제공하는 어댑터입니다.
주요 기능
- 분산 시스템 지원: 여러 서버 인스턴스 간 상태 동기화 가능
- 데이터 유지 관리: 서버 재시작 후에도 연결 정보와 세션 데이터 유지
- TTL(Time-To-Live) 인덱스: 만료된 데이터 자동 정리 기능
- 확장성: 대규모 사용자와 방을 효율적으로 관리
- 메타데이터 저장: 연결 시간, 사용자 정보 등 자동 기록
4. 구현
실제 구현시 추천하는 폴더 및 파일 구조
이해를 돕기 위해 예시코드에는 모든 내용을 한번에 작성했지만 실제 사용시 기능별로 분리 해서 사용 가능함
// example
/server
├── index.ts // 서버 진입점
├── socket.ts // 소켓 이벤트 정의 특히 path 별로 각각의 소켓 서비스를 구분할 경우 분리하는 것을 추천
├── db.ts // MongoDB 연결 및 컬렉션 세팅 (adapter 내용도 db 에서 처리하는 것도 방법)
├── adapter.ts // MongoDB 어댑터 설정 어뎁터까지
├── env.ts // 환경 변수 설정
예시
import { createAdapter } from "@socket.io/mongo-adapter"; // db 연결 관련
import dotenv from "dotenv";
import express from "express";
import { createServer } from "http";
import { MongoClient } from "mongodb";
import { Server } from "socket.io";
dotenv.config(); // 환경 변수 로드
// 1. 서버 설정
const app = express(); // express 서버
const httpServer = createServer(app);
// 2. MongoDB 연결 설정
const DB_URL = process.env.MONGODB_URL;
const DB_NAME = process.env.MONGODB_NAME;
// 3. mongo db 연결
const mongoClient = new MongoClient(DB_URL);
await mongoClient.connect();
const db = mongoClient.db(DB_NAME);
// 4. collection 생성
// 소켓 연결 정보를 저장할 컬렉션 생성
const collection = db.collection("socket_chat");
// TTL(Time To Live) 인덱스 생성 - 오래된 채팅 데이터 자동 삭제
collection.createIndex(
{ createdAt: 1 },
{
expireAfterSeconds: 3600, // 3600초(1시간)가 지나면 자동으로 삭제
background: true, // 백그라운드에서 인덱스 생성
},
);
// 5. Socket.IO 서버 설정
const chatServer = new Server(httpServer, {
cors: { origin: ["develop server url"], credentials: true },
// 서버 경로 설정
// 클라이언트에서 연결 시 예시: const socket = io('https://서버주소', { path: '/server-chat' });
// 실제 네트워 요청 URL 예시: https://서버주소/server-chat/socket.io/?EIO=4&transport=websocket
path: "/server-chat",
// MongoDB 어댑터 연결
adapter: createAdapter(collection, {
addCreatedAtField: true, // 문서가 저장될 때 자동으로 createdAt 필드를 추가
}),
});
// 6. 소켓 연결 이벤트 핸들러 설정
chatServer.on("connection", (socket) => {
console.log(`🔵 클라이언트 연결됨: ${socket.id}`);
// 📖 소켓 이벤트 핸들러 설정시 마지막 인자로 콜백함수를 받을 수 있으며 실제 서버내에서 실행되는 것이 아닌 클라이언트에서 실행 됩니다.
// 소켓 이벤트 핸들러의 마지막 인자로 전달되는 콜백함수(done)는 서버에서 실행되지 않고, 서버에서 클라이언트로 다시 전송되어 클라이언트 측에서 실행됩니다.
// 이는 Socket.IO의 "확인(acknowledgement)" 메커니즘으로 이벤트 처리 완료를 클라이언트에게 알리고 데이터를 반환하는 용도로 사용됩니다.
// 연결 해제 이벤트 핸들러
socket.on("disconnect", (reason) => {
console.log(`🔴 클라이언트 연결 해제: ${socket.id}, 이유: ${reason}`);
});
// 방 입장 이벤트 핸들러
socket.on("enter_room", (roomName: string, done: (roomName: string) => void) => {
socket.join("videoChatRoom"); // "videoChatRoom" 라는 room name 을 가지 room 에 입장
console.log(`📌 ${socket.id} joined room: ${roomName}`);
done(roomName);
});
// 방 퇴장 이벤트 핸들러
socket.on("leave_room", (roomName: string, done: () => void) => {
socket.leave(roomName);
console.log(`User left chat: ${socket.id}`);
done();
});
});
// 7. 서버 실행 및 포트 설정
httpServer.listen(3000, () => console.log("✅ 시그널링 서버 실행"));
// 8. 프로세스 종료 시 자원 정리
process.on("SIGINT", async () => {
console.log("서버를 종료합니다...");
try {
await mongoClient.close();
console.log("MongoDB 연결을 종료했습니다.");
process.exit(0);
} catch (error) {
console.error("서버 종료 중 오류 발생:", error);
process.exit(1);
}
});
'websocket & webRTC' 카테고리의 다른 글
3. RTCPeerConnection 이해와 관련된 주요 인터페이스 (0) | 2025.04.22 |
---|---|
2. 시그널링 서버 연결 및 미디어 장치 연결 (0) | 2025.04.18 |
0. Web RTC 이해 (0) | 2025.04.16 |
Socket.IO 기본 사용법 (0) | 2025.03.28 |
웹 소켓(WebSocket) 이해 (0) | 2025.03.23 |