React4분
Socket.io
2025년 5월 8일
“Socekt.IO는 무엇이며, 어떻게 동작하지?”
1. Socket.IO란?
- Socket.IO는 WebSocket을 기반으로 한 실시간 양방향 통신 라이브러리
- 서버와 클라이언트 간의 데이터 교환을 쉽게 할 수 있도록 도와줌
- 웹소켓을 지원하지 않는 환경에서도 작동 가능
2. Socket.IO와 WebSocket의 차이
특징 | WebSocket | Socket.IO |
---|---|---|
프로토콜 | WebSocket | WebSocket + HTTP |
자동 재연결 | ❌ | ✅ |
이벤트 기반 메시징 | ❌ | ✅ |
네임스페이스 | ❌ | ✅ |
방(Room) 기능 | ❌ | ✅ |
HTTP 폴백 지원 | ❌ | ✅ |
결론: WebSocket보다 확장성이 뛰어나고, 추가 기능(방, 네임스페이스, 미들웨어 등)이 많아 실시간 채팅, 게임, 주식 정보, IoT 등에 적합
3. Socket.IO 기본 사용법
3-1 서버(Node.js 기준) 설정
설치
bashnpm install socket.io express
서버 코드 (server.js
)
javascriptconst 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, {
cors : { origin: "*"} // CORS 설정
});
io.on("connection", (socket) => {
console.log("클라이언트 연결:", socket.id);
socket.on("message", (msg) => {
console.log(`메시지 받음: ${msg}`);
io.emit("message", msg);
});
socket.on("disconnect", () => {
console.log("클라이언트 연결종료:", socket.id);
});
});
server.listen(3000, () => console.log("서버 실행중..."));
3-2. 클라이언트(React)
설치
bashnpm install socket.io-client
React 클라이언트 코드(App.tsx
)
typescriptimport { useEffect, useState } from "react";
import { io } from "socket.io-client";
const socekt = io("http://localhost:3000");
const App = () => {
const [messsages, setMessages] = useState<string[]>([]);
const [input, setInput] = useState("");
useEffect(() => {
socket.on("message", (msg) => {
setMessages((prev) => [...prev, msg]);
});
return () => {
socket.off("message");
};
}, []);
const sendMessage = () => {
socket.emit("message", input);
setInput("");
};
return (
<div>
<ul>{messages.map((msg, i) => <li key={i}>{msg}</li>)}</ul>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button onClick={sendMessage}>전송</button>
</div>
);
};
export default App;
클라이언트에서 메시지를 보내면 서버에서 받아서 전체 클라이언트에게 전달됨
4. Socket.IO 핵심 기능
4-1 이벤트 기반 통신
typescriptsocekt.on("customEvent", (data) => {
console.log("받은 데이터", data);
socket.emit("responseEvent", { success: true});
});
typescriptsocket.emit("customEvent", { username: "Alice" });
socket.on("responseEvent", (data) => {
console.log("서버 응답", data);
})
4-2 방(Room) 기능
같은 목적을 가진 사용자끼리 그룹을 만들어 메시지를 주고받을 수 있음
서버
javascriptsocket.on("joinRoom", (room) => {
socket.join(room);
io.to(room).emit("message", `방 ${room}에 새 유저 입장`);
});
socket.on("leaveRoom", (room) => {
socket.leave(room);
io.to(room).emit("message", `방 ${room}에서 유저 퇴장`);
});
클라이언트
typescriptsocekt.emit("joinRoom", "room1");
socekt.emit("leaveRoom", "room1");
4-3. 네임스페이스 (Namespace)
특정 기능별로 채널을 분리해서 사용 가능
서버
javascriptconst chat = io.of("/chat");
chat.on("connection", (socket) => {
console.log("채팅 네임스페이스 연결됨");
socket.on("message", (msg) => {
chat.emit("message", msg);
});
});
클라이언트
typescriptconst chatSocket = io("http://localhost:3000/chat");
chatSocket.emit("message", 안녕하세요!");
4-4 미들웨어 (인증, 로깅)
javascriptio.use((socket, next) => {
const token = socket.handshake.auth.token;
if (token === "valid_token") {
next();
} else {
next(new Error("인증실패"));
}
});
5. 고급 기능
5-1. 메시지 전송 방법
javascriptsocket.to(socketId).emit("message", "개인 메시지");
io.to("room1").emit("message", "방 메시지");
socket.broadcast.emit("message", "모두에게");
5-2. 서버 간 확장 (Redis Adapter)
여러 대의 서버에서 같은 WebSocekt 이벤트를 공유할 수 있도록 Redis 활용
bashnpm install socekt.io-redis
javascriptconst redisAdapter = require("socekt.io-redis");
io.adapter(redisAdapter({ host: "localhost", port: 6379}));
서버가 여러 대라도 모든 클라이언트에 동일한 메시지를 보낼 수 있음
결론
Socekt.IO
는 웹 소켓을 기반으로 한 실시간 통신 라이브러리로, 이벤트 기반 메시징, 방 기능, 네임스페이스, 미들웨어 등을 지원하여 채팅, 게임, IoT, 실시간 알림 시스템 등에 최적화 됨- WebSocekt보다 유연한 폴백 기능을 제공하며, 서버 확장 시 Redis Adapter와 함께 사용 가능
Spring Boot에서 Socket.IO 구현하기
“Spring Boot에서 Socket.IO 기능을 어떻게 구현할까?”
1. WebSocket vs Socket.IO
Spring Boot의 경우 기본적으로 WebSocket
을 지원하지만, Socket.IO의 방(Room), 네임스페이스, 자동 재연결 기능은 제공 x 따라서 Socket.IO 스타일의 기능을 Spring Boot에서 구현 하려면 Spring WebSocket + STOP
또는 Netty Socket.IO
라이브러리를 사용할 수 있음
기능 | Spring WebSocket | Socket.IO |
---|---|---|
자동 재연결 | ❌ | ✅ |
이벤트 기반 메시징 | ✅ | ✅ |
방(Room) 기능 | ❌(직접 구현 필요) | ✅ |
네임스페이스 | ❌(직접 구현 필요) | ✅ |
HTTP 폴백 | ❌ | ✅ |
결론: Spring Boot에서는 WebSocket과 STOMP를 사용해 Socket.IO와 유사한 기능을 구현할 수 있음
2. Spring Boot WebSocekt 설정
2-1. WebSocket 의존성 추가
xml<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocekt</artifactId>
</dependency>
2-2. WebSocekt 설정 (WebSocketConfig.java
)
javaimport org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new ChatWebSocketHandler(), "/ws/chat")
.setAllowedOrigins("*"); // CORS 허용
}
}
ChatWebSocketHandler
에서 WebSocket 메시지를 처리
3. WebSocket 핸들러 구현
3-1 WebSocket 핸들러 (ChatWebSocketHandler.java
)
javaimport org.springframework.web.socket.*;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.util.concurrent.CopyOnWriteArrayList;
public class ChatWebSocketHandler extends TextWebSocketHandler {
private static final CopyOnWriteArrayList<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessions.add(session);
System.out.println("✅ 새로운 클라이언트 연결: " + session.getId());
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
System.out.println("📩 메시지 받음: " + message.getPayload());
// 모든 클라이언트에게 메시지 전송
for (WebSocketSession s : sessions) {
s.sendMessage(new TextMessage(message.getPayload()));
}
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessions.remove(session);
System.out.println("❌ 클라이언트 연결 종료: " + session.getId());
}
}
클라이언트가 메시지를 보내면, 모든 클라이언트에게 전달됨
4. STOP와 SockJS 활용 (Socket.ID 유사 기능 구현)
4-1. STOMP란?
- STOMP(Simple Text Oriented Messaging Protocol)는 메시지 브로커(RabbitMQ, ActiveMQ)와 함께 사용 가능
- 클라이언트가 서버와 주제(topic) 기반으로 소통 (Socket.IO의 네임스페이스와 비슷함)
4-2. WebSocket 설정 (WebSocketConfig.java
)
javaimport org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic"); // 클라이언트 구독 경로
config.setApplicationDestinationPrefixes("/app"); // 클라이언트 메시지 전송 경로
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws") // WebSocket 엔드포인트
.setAllowedOrigins("*")
.withSockJS(); // SockJS 지원
}
}
4-3. 메시지 컨트롤러 (ChatController.java
)
javaimport org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
@Controller
public class ChatController {
@MessageMapping("/chat") // 클라이언트 메시지 전송 주소 (/app/chat)
@SendTo("/topic/messages") // 모든 구독자에게 메시지 전송
public String sendMessage(String message) {
return message;
}
}
4-4. 클라이언트 (React)
typescriptimport { useEffect, useState } from "react";
import SockJS from "sockjs-client";
import { Stomp } from "@stomp/stompjs";
const socket = new SockJS("http://localhost:8080/ws");
const stompClient = Stomp.over(socket);
const App = () => {
const [messages, setMessages] = useState<string[]>([]);
const [input, setInput] = useState("");
useEffect(() => {
stompClient.connect({}, () => {
stompClient.subscribe("/topic/messages", (msg) => {
setMessages((prev) => [...prev, msg.body]);
});
});
return () => stompClient.disconnect();
}, []);
const sendMessage = () => {
stompClient.send("/app/chat", {}, input);
setInput("");
};
return (
<div>
<ul>{messages.map((msg, i) => <li key={i}>{msg}</li>)}</ul>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button onClick={sendMessage}>전송</button>
</div>
);
};
export default App;
5. 방(Room) 기능 구현
javaimport org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.messaging.handler.annotation.MessageMapping;
@Controller
public class ChatController {
private final SimpMessagingTemplate template;
public ChatController(SimpMessagingTemplate template) {
this.template = template;
}
@MessageMapping("/room/{roomId}")
public void sendMessage(String message, @DestinationVariable String roomId) {
template.convertAndSend("/topic/room/" + roomId, message);
}
}
/topic/room/{roomId}
구독 시 방 기능 구현 가능
결론
Spring Web Socket + STOMP
를 사용하면 **Socket.IO의 기능(방, 네임스페이스, 자동 재연결)**을 구현 가능- SockJS 지원으로 WebSocekt 미지원 환경에서도 동작
- RabbitMQ와 연결하면 확장성 증가
태그
#React#Socket