Socket.IO 룸을 활용한 실시간 통신 마스터하기

발행: (2025년 12월 22일 오후 01:57 GMT+9)
8 min read
원문: Dev.to

Source: Dev.to

Chandrashekhar Kachawa

Socket.IO는 웹 클라이언트와 서버 간에 실시간, 양방향, 이벤트 기반 통신을 가능하게 하는 강력한 라이브러리입니다. 모든 연결된 클라이언트에게 메시지를 브로드캐스트하는 것은 간단하지만, 실제 애플리케이션 대부분은 특정 사용자 그룹에게만 메시지를 보내야 합니다. 바로 이때 Socket.IO의 rooms 기능이 빛을 발합니다.

이 가이드는 Node.js에서 방을 생성하고 사용하는 방법을 단계별로 안내하며, 공개 공간과 비공개 공간 관리까지 모두 다룹니다.

방이란?

은 서버‑사이드 개념으로, 소켓을 함께 그룹화할 수 있게 합니다. 소켓은 joinleave 방을 할 수 있으며, 특정 방에 있는 모든 소켓에게 메시지를 브로드캐스트할 수 있습니다. 하나의 소켓은 동시에 여러 방에 있을 수 있습니다.

각 소켓은 고유한 socket.id 로 식별되는 방에 자동으로 가입합니다. 이는 특정 사용자에게 개인 메시지를 보내는 데 유용합니다.

기본 서버 설정

먼저, 필요한 패키지를 설치합니다:

pnpm install express socket.io

Create your main server file (e.g., server.js):

// server.js
import express from 'express';
import { createServer } from 'http';
import { Server } from 'socket.io';

const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {
  cors: {
    origin: '*', // Allow all origins for simplicity
  },
});

io.on('connection', (socket) => {
  console.log(`A user connected: ${socket.id}`);

  // Listen for a custom event to join a room
  socket.on('joinRoom', (roomName) => {
    socket.join(roomName);
    console.log(`${socket.id} joined room: ${roomName}`);

    // Broadcast to the specific room
    io.to(roomName).emit('message', `Welcome ${socket.id} to the ${roomName} room!`);
  });

  socket.on('disconnect', () => {
    console.log(`A user disconnected: ${socket.id}`);
  });
});

const PORT = process.env.PORT || 3000;
httpServer.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

방 생성 및 고유성

우리는 방을 명시적으로 생성하지 않았다는 것을 눈치채셨을 수도 있습니다.
방은 첫 번째 소켓이 입장할 때 암묵적으로 생성되며, 마지막 소켓이 떠날 때 자동으로 폐기됩니다.

방의 고유성은 단순히 이름(문자열)에 기반합니다. 이 이름들을 관리하는 것은 여러분 애플리케이션의 책임입니다.

Source:

고유 방을 보장하는 방법

공개 방

general, support, news와 같은 미리 정의된 사람이 읽을 수 있는 이름을 사용하세요.

비공개 방 (예: 직접 메시지)

관련된 두 사용자를 위한 일관되고 고유한 식별자가 필요합니다. 일반적인 전략은 고유 사용자 ID를 예측 가능한 순서로 결합하는 것입니다:

function getPrivateRoomName(id1, id2) {
  // Sort the IDs to ensure the room name is always the same
  // regardless of who initiates the chat.
  return [id1, id2].sort().join('-');
}

const roomName = getPrivateRoomName('userA_id', 'userB_id'); // "userA_id-userB_id"
socket.join(roomName);

이는 어떤 두 사용자도 항상 동일한 비공개 방을 공유하도록 보장합니다.

공개 방 vs. 비공개 방

공개 방과 비공개 방의 구분은 Socket.IO의 내장 기능이 아니라, 애플리케이션 로직에서 구현하는 패턴입니다.

공개 방

공개 방은 모든 사용자가 참여할 수 있는 방입니다. 클라이언트는 일반적으로 사용 가능한 공개 방 목록을 표시하고, 사용자는 그 중 하나를 선택해 입장합니다.

// Client-side code
const socket = io('http://localhost:3000');

// User joins the 'general' chat room
socket.emit('joinRoom', 'general');

socket.on('message', (data) => {
  console.log(data);
});

비공개 방

비공개 방은 접근이 제어됩니다. 특정 방에 사용자가 입장할 권한이 있는지 서버에서 항상 검증해야 합니다—보안에 매우 중요합니다.

// Server-side code
socket.on('joinPrivateRoom', ({ roomId }) => {
  // Example: Check if the user is authenticated and has permission
  const isAuthorized = checkUserAuthorization(socket.request.user, roomId);

  if (isAuthorized) {
    socket.join(roomId);
    io.to(roomId).emit('message', `${socket.id} has joined the private discussion.`);
  } else {
    socket.emit('error', 'You are not authorized to join this room.');
  }
});

Socket.IO 방을 사용할 때

  • 채팅 애플리케이션: 그룹 채팅, 직접 메시지, 혹은 주제 기반 토론.
  • 실시간 협업: 각 문서(예: Google Docs)를 방으로 만들고, 편집 내용을 협업자에게만 방송.
  • 멀티플레이어 게임: 게임 세션에 플레이어를 그룹화하고, 해당 세션에만 상태 업데이트 전송.
  • 알림 시스템: 사용자의 팀원이나 팔로워가 있는 방에 행동이 발생했을 때 알림 전송.

방을 사용하면 안 되는 경우

  • Simple Data Fetching: 일회성 데이터 조회의 경우, 표준 REST 또는 GraphQL API가 더 적합합니다. WebSockets는 불필요한 복잡성을 추가합니다.
  • Broadcasting to Everyone: 모든 연결된 클라이언트에게 메시지를 보내야 한다면, io.emit()을 직접 사용하세요—방이 필요 없습니다.
  • Unidirectional Updates: 그룹화가 필요 없는 가끔씩 서버‑클라이언트 푸시의 경우, Server‑Sent Events (SSE) 또는 롱 폴링을 고려하세요.

최종 업데이트

서버에서 클라이언트로만 데이터를 전송해야 하는 경우(예: 주식 티커, 뉴스 피드), Server‑Sent Events (SSE) 를 고려하세요. SSE는 HTTP 위에 구축된 더 간단한 프로토콜이며 이러한 시나리오에 충분히 적합합니다.

결론

Socket.IO 방은 확장 가능하고 실시간 애플리케이션을 구축하기 위한 기본 개념입니다. 소켓을 그룹화함으로써 통신을 효율적으로 관리하고 메시지가 의도된 수신자에게만 전달되도록 할 수 있습니다. 핵심은 방이 서버‑측 추상화이며, 그 “프라이버시” 또는 “공개성”은 전적으로 애플리케이션의 로직과 권한 검사에 의해 결정된다는 점을 기억하는 것입니다.

Back to Blog

관련 글

더 보기 »

2015년처럼 API를 작성하지 마세요

우리는 2025년에 살고 있으며, 많은 코드베이스가 여전히 API를 단순히 “JSON을 반환하는 엔드포인트”로만 취급합니다. API 설계가 기본 CRUD 라우트를 넘어 발전하지 않았다면, 당신은 sacr…

미래의 나 AI

이것은 Mux가 주최한 DEV의 Worldwide Show and Tell Challenge에 대한 제출물입니다 https://dev.to/challenges/mux-2025-12-03 내가 만든 것 FutureMe AI는 pers…