WebSocket

qkrrnjswo·2023년 5월 23일
0

공부 정리

목록 보기
4/24
post-thumbnail

Websocket이란?

  • 하나의 TCP 접속에 전이중 통신 채널을 제공하는 컴퓨터 통신 프로토콜
    TCP/UDP통신이 궁금하다면 클릭!
  • HTTP 포트 80과 443 위에 동작하도록 설계
  • HTTP와 호환을 달성하기 위해 웹소켓 핸드셰이크HTTP 업그레이드 헤더를 사용하여 HTTP 프로토콜에서 웹소켓 프로토콜로 변경

1. 전이중 통신 채널?

  • 전이중 통신(Full Duplex)
    두 대의 단말기가 데이터를 송수신하기 위해 동시에 각각 독립된 회선을 사용하는 통신 방식
  • 반이중, 단방향 통신 등이 있음

2. HTTP 업그레이드 헤더?

  • HTTP 업그레이드 헤더?
    • HTTP/1.1에서 추가된 헤더 필드: 자세한 내용
    • 반드시 Get Method를 사용

3. 웹소켓 핸드셰이크

  • TCP 방식에선 연결 과정이 필요
  • Opening Handshake
    • 핸드셰이크 요청(HTTP Upgrade)을 전송
    • 핸드셰이크 응답(코드 101)
    • 101코드는 '프로토콜 전환'을 서버가 승인했음을 알리는 코드

  • Data Transfer
    • 웹소켓 연결이 수립되면, 데이터 전송 파트가 시작
    • '메시지'로 데이터를 주고받음
    • 주기적으로 서로를 확인하는 heartbeat 패킷을 보냄

  • Close Handshake
    • 서버, 클라모두 컨트롤 프레임을 전송 가능
    • 컨트롤 프레임은 Closing Handshake를 시작하라는 특정한 컨트롤 시퀀스를 포함
    • 컨트롤 프레임 전송 -> 응답으로 Close 프레임을 전송
    • 종료 이후에 수신되는 모든 추가적인 데이터는 버려짐

4. WebSocket의 단점

  • 모든 클리이언트 브라우저에서 지원한다는 보장이 없다.
  • sever/client중간에 위치한 proxy가 upgrade헤더를 해석하지 못해 서버에 전달하지 못할 수 있다.
  • server/client 중간에 위치한 proxy가 유휴상태에서 도중에 커넥션을 종료할 수 있다.



Spring에 Websocket 적용

자세한 설명: 여기

//설정
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new SocketTextHandler(), "/user")
                .setAllowedOrigins("*")
                .withSockJS();
    }
}


//핸들러
public class SocketTextHandler extends TextWebSocketHandler {

    private final Set<WebSocketSession> sessions = ConcurrentHashMap.newKeySet();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        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.getString("user") + "!"));
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        sessions.remove(session);
    }
}



SockJS, Socket.io

  • WebSocket과 유사한 객체를 제공하는 라이브러리들

  • SockJS는 브라우저와 웹 서버 사이에 대기 시간이 짧은 전이중 도메인 간 통신 채널을 생성하는 일관된 브라우저 간 Javascript API를 제공

  • SockJS는 WebSocket 프로토콜을 지원하지 않는 환경에서도 작동

  • Socket.io는 node.js기반의 웹소켓 라이브러리

  • SockJSSTOMP라고 하는 메세지 프로토콜과 함께 사용




STOMP?

  • Streaming Text Oriented Messaging Protocol

  • WebSocket 위에서 동작하는 간단한 텍스트기반 메시지 프로토콜

  • 전송할 메시지의 유형, 형식, 내용들을 정의

  • 메시지 브로커라는 것을 활용, pub-sub(발행-구독) 방식으로 클라이언트와 서버가 쉽게 메시지를 주고받을 수 있도록하는 하위 프로토콜


1. STOMP Frame

COMMAND
header1:value1
header2:value2
 
Body^@
  • STOMP는 COMMAND, header, Body 라는 형식으로 골격을 정의해둠
--------------------------------------------

//요청 전송의 예

SEND
destination:/queue/trade
content-type:application/json
content-length:44

{"action":"BUY","ticker":"MMM","shares",44}^@

--------------------------------------------

//클라이언트 구독의 예

SUBSCRIBE
id:sub-1
destination:/topic/price.stock.*

^@

--------------------------------------------

//MESSAGE 명령의 예

MESSAGE
message-id:nxahklf6-1
subscription:sub-1
destination:/topic/price.stock.MMM
 
{"ticker":"MMM","price":129.45}^@

--------------------------------------------

2. STOMP 기반의 통신흐름

  • SEND → request → response → Message
    • 발신자는 destination 헤더에 /topic,/app을 넣어 메시지를 채널에 전달
    • /app의 경우 핸들러를 통해 spring로직을 거친후 /topic으로 반환
    • /topic들은 SipmleBroker에서 구독자들에게 메세지 전달

3. STOMP가 필요한 이유

  • STOMP 프로토콜은 웹소켓만을 위해 만들어진 프로토콜이 아니다.
    그러면 왜 WebSocket 위에서 같이 사용하는 것일까?

    • WebSocket은 Text, Binary 타입의 메시지를 양방향으로 주고받을 수 있는 프로토콜
    • 거대한 프로젝트일 때, 주고 받는 메시지에 대한 형식이 중요해짐
    • 정해진 형식을 파싱하는 로직도 필요
    • STOMP은 위 2개의 문제를 해결해준다!

4. 자료출처

https://faith-developer.tistory.com/194
https://www.egovframe.go.kr/wiki/doku.php?id=egovframework:rte3.5:ptl:stomp


5. MQ 를 활용한 STOMP

  • Message Queue을 활용 하여 STOMP을 활용한 예
  • Message Borker는 채널에 /topic 프로토콜 데이터가 왔을 시 가로챔
  • 그 후 MQ에 연결된 모든 어플리케이션에게 메시지를 전달하게 되는 구조



Spring에 STOMP 적용

자세한 설명: 여기

// 설정
@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("/ws-edit")
                .withSockJS();
    }
}


// 컨트롤러 부분
@MessageMapping("/hello")
@SendTo("/topic/greeting")
public void enterChatRoom(SimpMessageHeaderAccessor headerAccessor) throws Exception {
		ChatDto newchatdto = chatService.enterChatRoom(chatDto, headerAccessor);
		msgOperation.convertAndSend("/sub/chat/room" + chatDto.getRoomId(), newchatdto);
	}



참고

https://velog.io/@pbg0205/Socket%EC%86%8C%EC%BC%93
https://doozi0316.tistory.com/entry/HTTPHTTPS%EB%9E%80-TCP-UDP-HandShake-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC
https://kellis.tistory.com/65
https://velog.io/@msung99/%EC%9B%B9%EC%86%8C%EC%BC%93%EA%B3%BC-STOMP%EB%A5%BC-%ED%86%B5%ED%95%9C-%EC%8B%A4%EC%8B%9C%EA%B0%84-%ED%86%B5%EC%8B%A0-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0

0개의 댓글