Spring에서 웹 소켓(WebSocket) 사용하기

bagt13·2022년 12월 24일
5

Spring

목록 보기
11/12

WebSocket과 HTTP

Web Socket (웹 소켓)

서버와 클라이언트 간에 Socket Connection을 유지해서 언제든 양방향 통신 또는 데이터 전송이 가능하도록 하는 기술로써, sns, 화상 채팅, 증권 거래 등에서 널리 사용되고 있다.


WebSocket을 사용하는 이유

실시간 채팅 앱과 같은 요구사항들을 반영하기 위해 클라이언트에서 매번 HTTP 프로토콜을 통해 서버에 요청하는 것은 비효율적이다.

클라이언트에서 Ajax 통신 등으로 일부 보완할 수 있지만, Ajax도 결국 HTTP를 사용하기 때문에 여전히 문제가 되며, 웹 소켓을 통해 이를 해결할 수 있다.


WebSocket의 특징

  • WebSocket은 HTTP를 통해 최초 연결되며, 이후 일정 시간이 지나면 HTTP 연결은 자동으로 끊어지고 webSocket connection은 유지된다.

  • HTTP와 달리 WebSocket은 stateful 프로토콜이다.

  • HTTP는 stateless하기 때문에 서버에 변경사항이 생겨도 클라이언트에서 요청을 하지 않으면 변경사항이 적용되지 않지만, WebSocket은 지속적으로 connection을 유지하기 때문에 실시간으로 변경사항이 적용된다.

  • WebSocket은 HTTP와 동일한 port(80)를 사용한다.


WebSocket 사용 시 주의점

  • WebSocket은 stateful 프로토콜로써 connection을 항상 유지해야하기 때문에 트래픽이 많은 경우 서버에 부담이 될 수 있다.

  • 연결이 계속 유지되어야 하기 때문에, 연결이 끊어졌을 때 적절히 대응할 수 있어야 한다.



Spring에서 Websocket 사용하기

Configuration

  • @EnableWebsocket : 웹 소켓 통신에 대한 설정 파일임을 명시한다. 더 찾아보니, 얘는 웹 소켓 관련 설정을 자동으로 해주고, WebSocketConfigurer을 implement + override 하여 메서드를 customize 할 수 있는 것이다.

  • setAllowedOrigins : 허용할 uri를 지정한다. (default는 same-origin만 허용)


WebSocket을 브라우저가 지원하지 않는 경우, Socket.io, SockJS 등을 활용 할 수 있다. SockJS는 javascript library이며, addHandler().withSockJS() 의 형태로 사용하면 된다. SockJS를 사용할 경우 클라이언트에서도 WebSocket 대신 SockJS를 사용하는 코드를 넣어주어야 한다.


WebSocketHandler

TextWebSocketHandler : text message를 처리할 수 있는 handler 클래스이다.

이 클래스는 AbstractWebSocketHandler라는 추상 클래스를 상속하며, 이외에도 이 추상 클래스를 상속하는 BinaryWebSocketHandler, SockJSWebSocketHandler 등이 존재하며, 처리하는 데이터 타입에 따라 골라서 사용하면 될 것 같다.


AbstractWebSocketHandler



afterConnectionEstablished()

  • 메서드 이름 그대로 connection이 성립된 후 작동되는 메서드이다.

  • 여기서는 메서드를 다음과 같이 override 한다.

    • 최초 연결 시 세션을 서버에 저장한다.
    • 예제이기 때문에 단일 서버라고 가정하고 ConcurrentHashMap에 sessionId : session의 형태로 저장한다.
    • 접속 중인 모든 세션(유저)에 접속 메시지를 전송한다.
  • 정의해둔 메시지 스펙(Message)을 따라 데이터를 생성하고, WebSocketSession.sendMessage() 메서드를 통해 메시지를 전송하며, text message를 다루는 handler를 구현하기 때문에 인자로 TextMessage를 받는다.

    여기서는 모든 유저에게 전송해야 하기 때문에 forEach()를 통해 모든 세션에 메시지를 보낸다.


postman을 통해 지정해둔 웹소켓 서버 endpoint로 최초 접속 성공 시 다음과 같은 화면이 나온다.

웹소켓 서버 최소 연결 성공 (postman)


handleTextMessage() - 양방향 통신 로직

클라이언트가 메시지 전송 요청을 서버로 보내며, 서버는 세션과 데이터를 파라미터로 전달받는다. 여기서 세션은 전송자(sender), 데이터는 메시지(message)이다.

  • 전달 받은 세션을 통해 전송자를 지정하고, 데이터를 통해 정의한 메시지 스펙에 따라 메시지를 생성한다.

  • 여기서 전달 받은 데이터에는 수신자(receiver)의 세션ID가 포함되어 있으며, receiver.sendMessge()로 수신자에게 메시지를 전송한다.


Simple WebSocket Client라는 chrome 확장 도구로 메시지를 전송하고, 성공한다면 다음과 같은 결과를 확인할 수 있다.

로그 확인

브라우저 확인


이외에도 handleTransportError() 메서드를 override 하여 소켓 통신에 에러가 발생했을 때 클라이언트에게 오류 메시지를 보내는 등의 추가 조치를 할 수 있다.

또한, afterConnectionClosed() 메서드를 재정의하여 소켓 연결 종료 시 세션 삭제 + 연결 종료 메시지 전송 등의 조치를 취할 수도 있다.

profile
주니어 백엔드 개발자입니다😄

0개의 댓글