[영상후기] [10분 테코톡] ✨ 아론의 웹소켓&스프링

박철현·2024년 3월 30일
0

영상후기

목록 보기
147/160

movie

  • 웹소켓 : 전이중 통신 제공 -> 실시간성 보장
    • 실시간성을 보장하는 서비스
    • 게임, 채팅, 실시간 주식 거래 사이트 등

HTTP vs 웹소켓

  • HTTP에서도 실시간성을 보장하는 기법 존재
    • Polling : 클라이언트가 요청 계속 보내기
    • Long Polling : 요청을 보내고 커넥션 오랫동안 유지하기
    • Streaming : 커넥션 당 다중 요청 / 응답 가능
  • HTTP
    • 비연결성
    • 매번 연결 맺고 끊는 과정의 비용
    • 요청 - 응답 한 쌍의 구조
    • 매번 Header, Response의 정보가 생성되고 응답되고 계속 주고받아야 함(메서드, ..)
  • 웹소켓
    • 연결 지향
    • 한번 연결 맺은 뒤 유지
    • 양방향 통신
      • 연결된 채널을 통해 상대가 보낸 메세지 듣고있으면 됨
      • 연결할때만 HTTP Header등이 필요하고, 연결된 이후에는 새로 만들 필요가 없음
      • 통신에 사용되는 비용 줄일 수 있음
  • SockJS, Socket.io : 웹 소켓을 지원하지 않는 웹 브라우저에서도 웹소켓을 사용하는 것 같은 비슷한 기능 제공
    • 브라우저 웹소켓 지원 확인하고 안하면 이 기법들을 사용
    • Spring은 SockJS 지원
      • 웹소켓 지원하면 소켓 사용
      • 지원하지 않으면 Streaming
      • Streaming도 지원하지 않으면 Polling

Spring

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
	@Override
    public void registerWebSocketHandler(WebSocketHandlerRegistry registry) {
    registry.addHandler(new SocketTextHandler(), "/user")
    	.setAllowedOrigins("*")
        .withSockJS();
  }
}
  • 스프링에서 웹소켓 사용하려면 클라이언트가 보낸 통신 처리할 핸들러 필요
    • SocketTextHandler() : 직접 구현한 웹소켓 핸들러
    • /user : 웹소켓 연결 주소
    • setAllowedOrigins() : Cors 설정
      • Spring에서 WebSocket 사용할 때 same origin만 허용하는 것이 기본 정책
    • withSockJS() : SockJS 사용을 위한 설정
public class SocketTextHandler extends TextWebSocketHandler {
	private final Set<WebSocketSession> sessions = ConcurrentHashMap.newKeySet();
    
    @Override
    public void afterConnectionEstablished(WebSocketSession session) {
    sessions.add(session);
    }
    
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
    String payload = message.getPayload();
    JSONObject jsonObject = new JSONObject(payload);
    for(WebSocketSession s : sessions) {
    	s.sendMessage(new TextMessage("Hi" + jsonObject.get("user) + "! How may I Help you?"));
     }
  }
  
  @Override
  public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
  	sessions.remove(session);
 }
}
  • 웹소켓 프로토콜은 기본적으로 Text와 Binary Type 지원
    • 필요에 따라 Spring이 제공하는 TextWebSocketHandler 혹은 BinaryWebSocketHandler를 상속한 handler 생성하기만 하면 됨
// 커넥션이 맺어질 때
   @Override
    public void afterConnectionEstablished(WebSocketSession session) {
    // 컬렉션에 웹소켓 세션 추가
    sessions.add(session);
    }
 
// 커넥션이 끊어질 때
    @Override
  	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
    // 컬렉션에 웹소켓 세션 삭제
  	sessions.remove(session);
 }
  • WebSocketSession : WebSocket이 연결될때 생성되는 연결정보 담고 있는 객체
    • HTTP의 Session과는 다름
    • Handler에서 WebSocket 통신에 대한 처리를 하기 위해 session들을 컬렉션으로 담아서 관리하는 경우가 많음
      • 연결된 세션 관리하게 되면 모든 클라이언트에게 메세지를 보내는 것과 같은 처리를 할 수 있음
    	private final Set<WebSocketSession> sessions = ConcurrentHashMap.newKeySet();

Spring Messaging?

  • Spring boot에서 WebSocket 의존성 추가 하니 딸려오는 발표자의 문제 발생
  • 어떤것인지 설명

STOMP 프로토콜

  • Simple Text Oriented Messaging Protocol
  • 메시지 브로커를 활용하여 쉽게 메세지를 주고 받을 수 있는 프로토콜
    • Pub - Sub(발행 - 구독) : 발신자가 메시지를 발행하면 수신자가 그것을 수신하는 메시징 패러다임
    • 메세지 브로커 : 발신자의 메시지를 받아와서 수신자들에게 메시지를 전달하는 어떤 것
  • 웹소켓 위에 얹어 함께 사용할 수 있는 하위(서브) 프로토콜
  • 웹소켓만을 위해 생긴 프로토콜은 아님
    • 웹소켓과 같은 몇몇 양방향 통신 프로토콜에서 함께 사용할 수 있음
    • 스프링이 웹소켓 위에 얹어 사용하는 방법을 지원한다는 것

STOMP의 필요성

  • WebSocket은 Text, Binary 타입의 메세지 양방향으로 주고받을 수 있는 프로토콜
    • Message 어떤 형식으로 주고받을 지 정해진 규칙이 없음
    • 하지만 웹소켓만으로 간단한 프로젝트는 구현 가능
  • 프로젝트가 커지고 협업 사람이 많아진다면? 규칙 정의 및 parsing 필요
    • Client - Server 어떤 형식의 메세지를 주고 받을지
    • 주고 받는 Message Type은 어떤것인지?
    • Message의 본문과 설정 정보같은건 어떻게 구분할 것인지 등
  • STOMP를 사용하면 위와 같은 형식과 Parsing에 관해 고민할 필요가 없음
    • STOMP는 프레임 단위의 프로토콜
      • 커멘드
      • 헤더
      • 바디
    • 웹소켓만 사용했을 때 : 날것의 Message
    • STOMP 사용 : 커멘드, 헤더, 바디 형태의 메세지가 오고 갈 수 있음
      • 프레임 구축 or 해석 코드를 구현하지 않아도 프레임 형식의 메세지를 오고 가고 하게 할 수 있음(Spring)

통신 흐름

  • 상황 가정
    • 발신자는 구독자들에게 메시지를 보내고 싶음
    • 구독자들은 /topic 이라는 경로를 구독하는 가정
  • 발신자는 /topic 이라는 destination header로 넣어서 메세지를 송신할 수 있지만 서버 내에서 메세지 가공/처리를 위해 /app이라는 곳에 송신
    • 가공되거나 처리된 메세지를 /topic이라는 경로로 다시 전송 -> Message Broker에게 전달 -> 전달받은 메세지를 구독자들에게 최종적으로 전달
  • Server단 처리 or 메세지 가공 필요가 없다면 바로 Message Broker를 통해서 보내는 것도 가능

Spring - WebSocketMessageBroker

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketBrokerConfig implements WebSocketMessageBrokerConfigurer {
	@Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
    registry.enableSimpleBroker("/queue", "/topic");
    registry.setApplicationDestinationPrefixes("/app");
  }
  
  @Override
  public void registerStompEndpoints(StompEndpointRegistry registry) {
  	registry.addEndpoint("/gs-guide-websocket").withSockJS();
}
}
  • configureMessageBroker : MessageBroker 설정 부분
    • enableSimpleBroker()
      • 내장 브로커 사용
      • prefix가 붙은 메시지를 발생 시 브로커가 처리
        • "/queue", "/topic"부분
          • "/queue" : 메세지가 1:1 송신 컨벤션
          • "/topic" : 메세지가 1:N 송신 컨벤션(브로드 캐스팅)
      • 처리 후 구독자들에게 전달
    • setApplicationDestinationPrefixes()
      • 메시지 처리나 가공기 필요한 경우 핸들러로 라우팅 되는 Prefix
      • 핸들러 설정 아래와 같음
@Controller
public class GreetingController {
	@MessageMapping("/hello")
    @SendTo("/topic/greeting")
    public Greeting greeting(HelloMessage message) throws Exception {
    Thread.sleep(1000);
    return new Greeting)
    	"Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!");
        }
      }
  • @MessageMapping : STOMP 웹소켓 -> Message destination header와 MessageMapping에 설정한 경로가 일치하는 Handler가 처리
    • configuration에서 설정한 /app 과 합쳐져서 /app/hello 가 됨
  • @SendTo : handler 처리 완료 후 메세지 다시 보낼 경로
    • /topic이 붙었으니 simple broker로 전달됨
  • registerStompEndpoints : 웹소켓 addHandler 메소드와 비슷
    • addEndPoint()
      • 처음 웹소켓 handShake를 위한 주소
      • 웹소켓 연결 주소
      • 이전처럼 Handler 하나하나 추가할 필요 없음
        • Handler를 구현하는 방식이 아닌 Controller 방식으로 사용하기 때문
      • cors, SockJS 설정 가능

STOMP 사용 장점

  • 하위 프로토콜 혹은 컨벤션을 따로 정의할 필요 없다
  • 연결 주소마다 새로 핸들러를 구현하고 설정해줄 필요가 없다
  • 외부 Messaging Queue를 사용할 수 있다(RabbitMQ, 카프카, ..)
  • Spring Security를 사용할 수 있다
profile
비슷한 어려움을 겪는 누군가에게 도움이 되길

0개의 댓글

관련 채용 정보