이번에 진행하는 프로젝트에서 채팅 서버 관련 개발을 담당하게 되어 학습한 내용을 정리한 포스팅입니다.
WebSocket?
웹소켓은 기존의 단방향 HTTP 프로토콜과 호환되며, 양방향 통신을 제공하기 위해 개발된 프로토콜입니다.
웹소켓과 HTTP는 모두 OSI 7계층에 위치해 있으며 동시에 4계층 TCP에 의존합니다.
클라이언트에서 최초 연결 시 기존 HTTP 통신과 마찬가지로 3Way-Handshake를 통해 연결을 하고, 웹소켓 프로토콜을 통해 데이터를 송/수신합니다.
또한 HTTP프로토콜과의 호환을 달성하기 위해 Handshake과정에서 HTTP 업그레이드 헤더를 사용하여 HTTP프로토콜에서 웹소켓 프로토콜로 변경하는 과정이 있습니다.
웹소켓을 사용하는 이유
일반적으로 클라이언트와 서버 사이에 HTTP 통신을 진행할 경우 다음과 같은 특징때문에 실시간 통신이 안됩니다.
1. 서버는 클라이언트의 요청에 대한 응답만 줄 수 있음.
2. HTTP 통신의 Stateless 특징 때문에 서버는 클라이언트의 정보 가지고 있을 수 없음.
이번 프로젝트의 서비스 중 채팅 서비스를 구현하기 위해서는 클라이언트와 서버 사이에 실시간 통신이 보장되어야 하기에 웹소켓을 활용하여 해당 서비스를 구현하기로 했습니다.
다음으로 Springboot에서 웹소켓을 활용하여 WAS를 구축하는 과정입니다.
개발환경
Springboot : 3.2.2
JDK : 17
build.gradle 의존성 추가
implementation 'org.springframework.boot:spring-boot-starter'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springframework.boot:spring-boot-starter-websocket'
implementation 'org.springframework.boot:spring-boot-devtools'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
websocket 의존성 외 devtools와 lombok의 경우 프로젝트 개발의 편리성을 위해 의존성을 추가해줍니다.
참고로 devtools의 경우 Springboot에서 아래와 같은 5가지의 기능들을 제공하는 라이브러리입니다.
- Property Defaults
- Automatic Restart
- Live Reload
- Global Settings
- Remote Applications
Websocket Handler
@Component
public class WebSockChatHandler extends TextWebSocketHandler {
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
log.info("payload {}", payload);
TextMessage textMessage = new TextMessage("Welcome");
session.sendMessage(textMessage);
}
}
클라이언트들로부터 오는 메시지를 실질적으로 처리하는 핸들러입니다.
기본적으로 소켓통신은 서버와 클라이언트 간 1:N 관계를 형성합니다.
서버에서는 다양한 클라이언트로부터 오는 메시지를 처리하기위한 Handler가 필요합니다.
위 코드에서 TextWebSocketHandler를 상속받아 handleTextMessage 메서드를 재정의하여 사용하고 있습니다.
웹소켓의 경우 7계층 즉 상위에서 동작하는 프로토콜로 바이너리 이외에 문자열까지 처리할 수 있습니다.
상속받고 있는 TextWebSocketHandler의 경우 바이너리로 오는 메시지는 무시하고 문자열로 된 메시지만 처리하기 위한 클래스라고 생각하면 될 것 같습니다.
당연히 바이너리 데이터만 처리하는 BinaryWebSocketHandler 인터페이스 또한 존재합니다.
추가적인 부분은 Spring 공식문서를 참조하면 좋을 듯 합니다.
메서드 내부를 잠깐 살펴보자면 요청을 한 클라이언트의 웹소켓 세션과 문자열로 된 메시지를 매개변수로 받고 있습니다.
내부에서는 메시지의 내용(Payload)을 log로 찍어보며, Welcome이라는 메시지를 세션값을 활용하여 다시 되돌려 주는 간단한 로직입니다.
다음으로는 설정에 관한 클래스입니다.
WebsocketConfig
@RequiredArgsConstructor
@Configuration
@EnableWebSocket
public class WebSockConfig implements WebSocketConfigurer {
private final WebSocketHandler webSocketHandler;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(webSocketHandler, "/ws/chat").setAllowedOrigins("*");
}
}
기본적으로 lombok의 기능인 @RequiredArgsConstructor 어노테이션을 통해 별도의 코드없이 DI를 수행합니다.
또한 @Configuration을 통해 스프링 빈 등록 및 싱글톤을 보장함과 동시에 설정파일임을 알려줍니다.
@EnableWebSocket의 경우 웹소켓을 활성화하기 위한 어노테이션라고 생각하면 됩니다.
WebSocketConfigurer 인터페이스를 상속받아 WebSocket 요청 처리를 구성하는 콜백 메서드를 재정의하여줍니다.
메서드 내부는 요청 매핑을 구성하기 위한 registry의 addHandler 메서드를 통해 /ws/chat이라는 URL 경로로 웹소켓 연결을 지정해줍니다.
setAllowedOrigins("*")의 경우 Cors 요청을 허용하기 위함.
이제 웹소켓 통신을 하기위한 서버의 설정은 모두 끝마쳤습니다.
추가로 클라이언트 접속 시 부여되는 고유한 웹소켓 세션을 통해 클라이언트들을 관리하고, 개별 채팅방 구현까지 하기위한 레퍼런스는 아래를 참조해주시면 좋을 것 같습니다.
https://www.daddyprogrammer.org/post/4077/spring-websocket-chatting/
'Develop > SpringBoot' 카테고리의 다른 글
세션(Session) & 쿠키(Cookie) (0) | 2024.02.23 |
---|---|
[Swagger] 스프링 3.x Swagger 적용(With. SpringDocs) (1) | 2024.01.31 |
[Jasypt] application.properties 설정 암호화 (0) | 2024.01.29 |
[채팅 서버] Springboot + STOMP를 활용한 채팅 구현 (1) | 2024.01.26 |
[채팅 서버] STOMP, Message Broker (1) | 2024.01.24 |
개발 기술 블로그, Dev
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!