설정
서버 설정 (Node.js)
import { Server } from "socket.io"; const io = new Server(3000, { cors: { origin: "http://localhost:5173" } });
클라이언트 설정
import { io } from "socket.io-client"; const socket = io("http://localhost:3000");
Express와 함께 사용
import express from "express"; import { createServer } from "http"; import { Server } from "socket.io"; const app = express(); const server = createServer(app); const io = new Server(server);
서버 옵션
cors크로스 오리진을 위한 CORS 설정
path커스텀 경로 (기본: /socket.io)
pingInterval하트비트 간격 (ms, 기본 25000)
pingTimeout연결 끊김 전 타임아웃 (기본 20000)
maxHttpBufferSize최대 메시지 크기 바이트 (기본 1MB)
이벤트
내장 이벤트 (서버)
connection클라이언트 연결
disconnect클라이언트 연결 끊김
disconnecting클라이언트 연결 끊기는 중 (아직 룸에 있음)
error에러 이벤트
내장 이벤트 (클라이언트)
connect서버에 연결됨
disconnect서버에서 연결 끊김
connect_error연결 실패
reconnect재연결 성공
reconnect_attempt재연결 시도 중
연결 생명주기
io.on("connection", (socket) => { console.log(`connected: ${socket.id}`); socket.on("disconnect", (reason) => { console.log(`disconnected: ${reason}`); }); });
이벤트 발신
서버 발신
socket.emit("hello", { msg: "world" }); socket.emit("data", arg1, arg2); io.emit("broadcast", data);
클라이언트 발신
socket.emit("chat:message", { text }); socket.emit("update", data, (res) => { console.log("ack:", res); });
발신 패턴
socket.emit(ev, data)이 소켓에만 전송
io.emit(ev, data)모든 연결된 클라이언트에 전송
socket.broadcast.emit()발신자 제외 모든 클라이언트
io.to(room).emit()룸의 모든 클라이언트
socket.to(room).emit()발신자 제외 룸 멤버
브로드캐스트
브로드캐스트 메서드
io.emit("msg", data); socket.broadcast.emit("msg", data); io.to("room1").emit("msg", data); io.except("room2").emit("msg", data);
휘발성 및 압축
socket.volatile.emit()클라이언트 준비 안 됐으면 버림 (버퍼링 없음)
socket.compress(true).emit()메시지별 압축 활성화
io.local.emit()로컬 서버에만 브로드캐스트 (다중 노드)
socket.timeout(5000).emit()확인응답에 타임아웃을 설정하여 발신
룸 작업
socket.join("room-1"); socket.join(["room-1", "room-2"]); socket.leave("room-1"); io.to("room-1").emit("msg", data);
룸 속성
socket.rooms이 소켓이 속한 룸 집합
socket.id각 소켓은 자신의 ID 룸에 자동 참가
io.sockets.adapter.rooms모든 룸과 멤버의 맵
룸 패턴
socket.on("join:room", (room) => { socket.join(room); io.to(room).emit("user:joined", socket.id); }); socket.on("disconnecting", () => { for (const room of socket.rooms) { socket.to(room).emit("user:left", socket.id); } });
네임스페이스
네임스페이스 생성
const chat = io.of("/chat"); const admin = io.of("/admin"); chat.on("connection", (socket) => { chat.emit("user:online", socket.id); });
클라이언트의 네임스페이스 연결
const chat = io("http://localhost:3000/chat"); const admin = io("http://localhost:3000/admin");
동적 네임스페이스
io.of(/^\/project-\d+$/).on("connection", (socket) => { const ns = socket.nsp.name; console.log(`joined namespace: ${ns}`); } );
미들웨어
서버 미들웨어
io.use((socket, next) => { const token = socket.handshake.auth.token; if (isValid(token)) return next(); next(new Error("authentication failed")); });
네임스페이스 미들웨어
const admin = io.of("/admin"); admin.use((socket, next) => { if (socket.handshake.auth.role === "admin") return next(); next(new Error("not authorized")); });
미들웨어 속성
socket.handshake.auth클라이언트에서 전송된 인증 데이터
socket.handshake.headers초기 요청의 HTTP 헤더
socket.handshake.query연결 URL의 쿼리 파라미터
socket.data미들웨어에서 첨부한 임의 데이터
에러 처리
서버 측 에러
socket.on("action", (data, callback) => { try { const result = process(data); callback({ status: "ok", data: result }); } catch (err) { callback({ status: "error", msg: err.message }); } });
클라이언트 측 에러
socket.on("connect_error", (err) => { console.log("connection error:", err.message); }); socket.io.on("reconnect_failed", () => { console.log("reconnection failed"); });
클라이언트 재연결 옵션
reconnection자동 재연결 활성화 (기본 true)
reconnectionAttempts최대 시도 횟수 (기본 무한)
reconnectionDelay초기 지연 ms (기본 1000)
reconnectionDelayMax최대 지연 ms (기본 5000)
확인응답
클라이언트 발신, 서버 확인
// 클라이언트 socket.emit("save", data, (response) => { console.log("server ack:", response); }); // 서버 socket.on("save", (data, callback) => { callback({ saved: true, id: 42 }); });
서버 발신, 클라이언트 확인
// 서버 socket.emit("ping", (response) => { console.log("client ack:", response); }); // 클라이언트 socket.on("ping", (callback) => { callback("pong"); });
타임아웃 포함
socket.timeout(5000).emit("save", data, (err, response) => { if (err) console.log("timeout!"); else console.log("ack:", response); } );
일반 패턴
채팅 룸
io.on("connection", (socket) => { socket.on("chat:join", (room) => { socket.join(room); socket.to(room).emit("chat:joined", socket.id); }); socket.on("chat:message", ({ room, text }) => { io.to(room).emit("chat:message", { from: socket.id, text }); }); });
온라인 상태
const users = new Map(); io.on("connection", (socket) => { users.set(socket.id, socket.handshake.auth); io.emit("users:list", [...users.values()]); socket.on("disconnect", () => { users.delete(socket.id); io.emit("users:list", [...users.values()]); }); });
속도 제한
io.use((socket, next) => { const ip = socket.handshake.address; if (rateLimiter.consume(ip)) return next(); next(new Error("rate limit exceeded")); });