Websocket

ParkIsComing·2024년 5월 26일
post-thumbnail

특징

  • full-duplex(양방향 통신) 지원
  • OSI 7-layer의 L7 프로토콜
  • L4 TCP에 의존
  • HTTP 80,443 포트 위에서 동작하도록 설계되었기 때문에 HTTP와 긴밀하게 동작한다.
  • Polling 방식보다 더 낮은 부하를 사용하여 통신할 수 있게 한다.
  • wswss라는 URI를 사용한다.
    • ws: 암호화되지 않은 연결에 사용. ws://와 같은 형식으로 작성하면 된다.
    • wss: 암호화된 연결에 사용. TLS를 통과해 전달되므로 송신자측에서 데이터가 암호화, 수신자측에서 복호화된다. wss://와 같은 형식으로 작성하면 된다.

동작 원리

1. Open handshake

웹소켓 연결을 위해서는 핸드쉐이크 요청을 전송하고 이에 대해 핸드쉐이크 응답(HTTP Status 101)를 받아야 한다.

101 Switching Protocol
서버가 전환되는 프로토콜을 가리킨다.
프로토콜은 클라이언트로부터 받은 Upgrade 헤더에 명시한다.

예시는 다음과 같다.

  1. 클라이언트측에서 요청
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
  1. 서버에서 응답
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

이렇게 TCP에 의존하는 HTTP 프로토콜로 웹소켓 연결을 위한 handshake를 수행하기 때문에, websocket 연결 후에도 HTTP 프로토콜 사용시에 TCP 연결로 생성된 socket을 그대로 사용한다..! (물론 이후로 HTTP 연결은 종료. 즉 HTTP 프로토콜을 더이상 사용하지 않는다.)

2. Transfer data

frame이라고 부르는 데이터 조각을 통해 이루어진다.

frame의 종류

  • text frame : 텍스트 데이터가 담긴 frame
  • binary data frame : 이진 데이터가 담긴 frame
  • ping/pong frame : 커넥션이 유지되고 있는지 확인하기 위한 frame. 서버나 브라우저가 자동으로 만들어 전송한다.
  • connection close frame : 커넥션 종료를 위해 연결 주체 중 한쪽에서 보내는 frame

사실상 브라우저 환경에서는 text / binary data frame만 다루게 된다.

3. Close handshake

웹소켓 연결을 종료하는 과정도 hamndshake로 동작한다. 앞서 언급한 connection close frame을 클라이언트와 웹 서버 중 한쪽이 전송하면 handshake를 시작할 수 있다. frame에는 상태 코드와 이유가 포함될 수 있다. 다른 한 쪽이 프레임을 수신하면 마찬가지로 connection clsoe frame을 전송하여 응답해야 한다. connection close frame이 양방향으로 전송되고, 수신되면 websocket 연결은 종료된다.

참고로 웹소켓 연결이 종료되면, 아래 L4의 TCP 연결도 종료된다.(4-way handshaking)

Client                Server
  |                     |
  |-- Close Frame ----->|
  |                     |
  |<-- Close Frame -----|
  |                     |
  |--- TCP FIN -------->|
  |                     |
  |<-- TCP FIN  --------|
  |                     |

🆚 SSE

  • 가장 큰 차이점은 통신 방향이다. Websocket은 양방향, SSE는 단방향이기 때문에 클라이언트가 데이터를 보낼 필요가 있을 때는 Websocket을 사용한다.
  • Websocket은 서버와 연결이 끊겼을 때 자동으로 연결해주는 기능이 없기 때문에 스스로 코드를 짜야되지만 SSE는 자동으로 3초마다 한 번씩 확인을 한다.

🆚 Polling / Long Polling

Polling

  • 전통적인 ajax 어플리케이션에서 사용되던 방식으로, 일정한 주기로 서버에 HTTP 요청을 보내 데이터를 받아오는 방식이다.
  • 새로운 데이터의 유무와는 상관없이 일정 간격으로 계속 요청을 보내는 것이다.
  • 단점 : 데이터가 짧은 간격으로 업데이트 되는 경우 문제가 된다.
    • 요청 간격을 짧게 하자니 서버가 받는 부하(잦은 HTTP Connection)가 커진다.
    • 요청 간격을 느릴자니 실시간성이 떨어진다.

Long Polling

  • Polling 방식과 유사하나, 서버에 요청을 보냈을 때 응답할 데이터가 없다면 서버는 일정 시간 기다리다가 데이터가 생기면 클라이언트에게 응답을 보내는 것이 차이점이다. (그 기간동안에도 새로 생기는 데이터가 없으면 빈 응답을 보낸다.)
  • 응답을 받은 클라이언트는 서버에게 (거의 바로) 다시 요청을 보낸다.
  • 단점 : 이또한 데이터가 빈번하게 바뀌면 Polling보다 더 많은 요청과 응답을 하면서 자원을 소모시킬 수 있다.

Spring에서 Websocket 사용

@Configuration 어노테이션을 사용하는 클래스에 @EnableWebSocketMessageBroker을 추가하여 Spring에서 Websocket을 사용할 수 있다.

WebSocketMessageBrokerConfigurer 인터페이스를 구현하여 STOMP와 같은 simple messaging 프로토콜들을 다루기 위한 메세지를 생성하고 처리할 수 있다.

STOMP

  • Simple Text Oriented Messaging Protocol
  • 메시징 프로토콜로, WebSocket을 포함한 다양한 전송 프로토콜 위에서 동작할 수 있다.
    간단한 메시지를 전송하기 위한 프로토콜로 메시지 브로커를와 publisher - subscriber 방식을 사용한다.
@Configuration
@RequiredArgsConstructor
@EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {
    private final StompHandler stompHandler;
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint(("/chat"))
                .setAllowedOriginPatterns("*")
                .withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic/");
        registry.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.interceptors(stompHandler); //stomp 메시지 핸들링
    }

}

0개의 댓글