스프링부트 소켓서버 만들기 예제
1) WebSocket 서버 예제 (Spring Boot + STOMP)
웹소켓을 직접 다루기보다, 메시지 라우팅이 편리한 STOMP 프로토콜을 함께 쓰면 채팅 등 브로드캐스트 구조를 쉽게 구현할 수 있습니다.
프로젝트 설정
- Spring Initializr로 생성- Dependencies: Spring Web, WebSocket, Lombok(선택), Spring Boot DevTools(선택)
 
- Gradle 기준 build.gradle 예시:
gradle
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-websocket'
    implementation 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}WebSocket/STOMP 설정 클래스
java
// WebSocketConfig.java
package com.example.websocketdemo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.*;
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    // STOMP 엔드포인트 등록: 클라이언트가 연결하는 URL
    
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws")          // 예: ws://localhost:8080/ws
                .setAllowedOriginPatterns("*")
                .withSockJS();               // 필요 시 SockJS 폴백
    }
    // 메시지 브로커 설정
    
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        // 서버 -> 클라이언트로 브로드캐스트할 목적지(prefix)
        registry.enableSimpleBroker("/topic", "/queue");
        // 클라이언트 -> 서버로 보낼 메시지의 prefix (컨트롤러 @MessageMapping 과 연결)
        registry.setApplicationDestinationPrefixes("/app");
    }
}메시지 DTO
java
// ChatMessage.java
package com.example.websocketdemo.model;
import lombok.*;
 
public class ChatMessage {
    private String sender;
    private String content;
}메시지 핸들러(Controller)
java
// ChatController.java
package com.example.websocketdemo.controller;
import com.example.websocketdemo.model.ChatMessage;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
public class ChatController {
    // 클라이언트가 /app/chat 으로 보내면, /topic/messages 로 브로드캐스트
    
    
    public ChatMessage broadcast(ChatMessage message) {
        // 필요한 로직(검증, 필터링 등)을 이곳에서 수행
        return message; // 그대로 반환하면 구독자들에게 전달
    }
}테스트용 클라이언트 (HTML)
아래 파일을 src/main/resources/static/index.html로 두고 서버 실행 후 http://localhost:8080 접속하여 테스트할 수 있습니다.
html
<html lang="ko">
<head>
  <meta charset="UTF-8" />
  <title>WebSocket STOMP 테스트</title>
  <script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/stompjs@2.3.3/lib/stomp.min.js"></script>
</head>
<body>
  <h2>간단 채팅</h2>
  <input id="sender" placeholder="닉네임" />
  <input id="content" placeholder="메시지" />
  <button onclick="sendMessage()">전송</button>
  <div id="logs"></div>
  <script>
    let stompClient = null;
    function connect() {
      const socket = new SockJS('/ws');
      stompClient = Stomp.over(socket);
      stompClient.connect({}, () => {
        // 서버 브로드캐스트 구독
        stompClient.subscribe('/topic/messages', (msg) => {
          const body = JSON.parse(msg.body);
          const line = `[${body.sender}] ${body.content}`;
          document.getElementById('logs').innerHTML += `<div>${line}</div>`;
        });
      });
    }
    function sendMessage() {
      const sender = document.getElementById('sender').value || '익명';
      const content = document.getElementById('content').value;
      const payload = { sender, content };
      stompClient.send('/app/chat', {}, JSON.stringify(payload));
    }
    window.onload = connect;
  </script>
</body>
</html>실행 방법
- 애플리케이션 실행: gradle bootRun 또는 IDE에서 Spring Boot 앱 실행
- 브라우저에서 두 개의 탭을 열어 메시지를 전송하면 서로에게 브로드캐스트되는 것을 확인하실 수 있습니다.
2) 간단한 WebSocket(핸드셰이크만, STOMP 없이) 예제
STOMP 없이 순수 WebSocket을 쓰고 싶을 경우 아래처럼 Handler를 구현할 수 있습니다.
java
// SimpleWebSocketHandler.java
package com.example.websocketdemo.ws;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class SimpleWebSocketHandler extends TextWebSocketHandler {
    private final Set<WebSocketSession> sessions = ConcurrentHashMap.newKeySet();
    
    public void afterConnectionEstablished(WebSocketSession session) {
        sessions.add(session);
    }
    
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 받은 메시지를 모든 세션에 브로드캐스트
        for (WebSocketSession s : sessions) {
            if (s.isOpen()) {
                s.sendMessage(message);
            }
        }
    }
    
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
        sessions.remove(session);
    }
}java
// RawWebSocketConfig.java
package com.example.websocketdemo.config;
import com.example.websocketdemo.ws.SimpleWebSocketHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.*;
public class RawWebSocketConfig implements WebSocketConfigurer {
    
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(simpleWebSocketHandler(), "/ws-raw")
                .setAllowedOriginPatterns("*");
    }
    
    public SimpleWebSocketHandler simpleWebSocketHandler() {
        return new SimpleWebSocketHandler();
    }
}클라이언트 예시:
html
<script>
  const ws = new WebSocket("ws://localhost:8080/ws-raw");
  ws.onmessage = (e) => console.log("받음:", e.data);
  ws.onopen = () => ws.send("안녕하세요!");
</script>3) 순수 TCP 소켓 서버 예제 (Netty 또는 Java Socket)
Spring Boot 내부에서 간단히 TCP 소켓을 열고 싶다면, CommandLineRunner로 서버 소켓을 띄울 수 있습니다. 다만 운영 환경에서는 Netty 같은 프레임워크 사용을 권장드립니다.
java
// TcpServerRunner.java
package com.example.websocketdemo.tcp;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServerRunner implements CommandLineRunner {
    
    public void run(String... args) throws Exception {
        new Thread(this::startServer, "tcp-server-thread").start();
    }
    private void startServer() {
        try (ServerSocket serverSocket = new ServerSocket(9090)) {
            System.out.println("TCP 서버 시작: 9090");
            while (true) {
                Socket client = serverSocket.accept();
                new Thread(() -> handleClient(client)).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private void handleClient(Socket client) {
        try (BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
             BufferedWriter out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()))) {
            String line;
            while ((line = in.readLine()) != null) {
                // 에코 반환
                out.write("echo: " + line);
                out.newLine();
                out.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}클라이언트 테스트:
- 터미널에서: telnet localhost 9090 후 문자열 입력
- 또는 netcat: nc localhost 9090
댓글
댓글 쓰기