Skip to content

웹소켓 #
Find similar titles

Structured data

Category
Programming

웹 소켓 #

웹 소켓 이란? #

  • 대부분의 웹 기반 클라이언트-서버 애플리케이션에서 HTTP의 요청-응답 모델은 서버로부터 클라이언트로의 정보 전송의 요청이 발생한 경우에서만 이루어지는 한계를 지님(Connection Less)
  • 이러한 이유로 클라이언트-서버 간의 실시간 통신이 불가능
  • 이를 해결하기 위해 Long-full, comet 등의 기술이 등장하였으나 full-duplex(전이 중) 통신에 대한 요구는 꾸준히 증가
  • 웹 소켓 프로토콜은 HTTP 연결을 웹 소켓으로 업그레이드하기 위한 기술로, 이를 통해 웹 소켓의 양 종단 간의 독립된 양방향 메시지 전송이 가능

Life Cycle #

  • 클라이언트 Peer에서 HTTP 핸드쉐이크 요청으로 웹 소켓 통신 시작
  • 이에 대해 서버 Peer에서 이 핸드쉐이크 요청받아 핸드쉐이크 응답을 전송
  • 완전하게 대칭인 전이 중 양방향 연결이 수립
  • 어느 한쪽에서 연결을 종료할 때까지 양 Peer는 서로 간의 메시지 송수신이 가능

Java 웹 소켓 #

프로그래밍 방식 #

  • JSR 356 스펙은 대부분의 JavaEE 개발자들이 쉽게 적용할 수 있도록 표준패턴과 기술에 따라 Annotation & Injection 기법을 지원
  • 두 가지 모두 event-driven 방식에 기반

JSR 356 #

  • JSR 356은 자바 클라이언트뿐만 아니라 서버 애플리케이션까지 웹 소켓 연결로 통합할 수 있는 웹 소켓 프로토콜 지원 스펙 의미
  • 이에 따라 실제 웹 소켓 구현에 독립적인 웹 소켓 기반 애플리케이션 구현이 가능
  • JAVA EE 7에 표준 스펙으로 채택

Broker #

  • 뜻 그래도 중개자의 역할
  • webSocket을 이용한다는 것은 클라이언트 간의 관계가 아닌 서버와 클라이언트의 peer to peer 관계이므로 메시지를 받아 정리하고 브로드캐스팅할 브로커 역할이 필요
  • Spring 내에 SimpleBroker 사용할 수도 있고 외부의 rabbitMQ 같은 플러그인을 사용하여 중개자를 둘 수 있음(외부 플러그인 사용 시 spring은 일종의 서버 역할만 수행)

Interface-driven programming #

  • Endpoint 인터페이스의 구현체를 통해 고정된 시그니처의 메서드로 웹 소켓 이벤트를 처리할 수 있음
  • 어노테이션 지향 방식과 다르게 고정적인 프로그래밍 방법론에 따라, 고정된 시그니처의 메서드들을 가진 인터페이스(Endpoint)를 상속하여 구현

endPoint #

public class MyOwnEndpint extends javax.websocket.Endpoint{
    public void onOpen(Session session, EndpointConfig config) {}
    public void onClose(Session session, CloseReason closeReason) {}
    public void onError(Session session, Throwable throwable) {}
}
  • 수신된 메시지에 대한 핸들러는 Message Handler. Partial 나 Message Handler. Whole 구현체로 작성할 수 있고, 처리할 수 있는 메시지의 종류는 각 구현체의 generic type으로 결정되며, 메시지 핸들러들은 웹 소켓 연결 직후 open 이벤트 핸들러에서 해당 세션에 등록하는 과정을 거쳐야만 함

open #

public void onOpen(Session session, EndpointConfig config){
    session.addMessageHandler(new MessageHandler(){...});
}
  • 수신메시지는 각 메시지 타입을 직접 핸들링하거나, 메시지 타입 복부 호화를 위한 Encoder, Decoder 등이 제공되는 등 java WebSocket API 등의 여러 가지 지원 요소들을 통해 다양한 형태의 메시지 송수신이 가능

  • 가장 기본적인 메시지 전송 형태는 텍스트 기반 메시지, 바이너리 메시지, pong 메시지 등이 있는데, 이러한 메시지들은 인터페이스 지향 방식을 사용하는 경우, 각기 다른 타입의 MessageHandler를 등록하여 처리할 수 있고, 어노테이션 지향 방식을 사용하는 경우, OnMessage 메서드의 파라미터 타입으로 각기 다른 메시지 핸들러를 작성할 수 있음

SockJS #

  • 웹 소켓 API 지원 여부가 브라우저 혹은 웹서버에 따라 다른 관계로 다양한 우회 기법들을 추상화하여 공통된 인터페이스를 정의한 라이브러리
  • SockJS는 http 프로토콜을 사용하기 때문에 웹 소켓 프로토콜을 지원하지 않는 런타임 환경에서도 애플리케이션의 코드를 변경하지 않고, 양방향 통신 가능
  • 클라이언트에서 연결에 대한 요청을 보냈을 때 4번의 요청을 보내 연결을 수립
  • handler 등록에 websocket:sockjs 추가
  • webSocket 사용 시 ws:// 의 경로를 사용해야 하나 sockJS는 http 위에서 돌아가므로 contextPath/(endPoint) 형식으로 uri 작성
  • JSP에서는 sockJS에 대한 CDN 설정 후 sockJS 객체를 생성하여 사용

STOMP(Simple Text Oriented Message Protocol) #

STOMP frame 구조 #

  • stomp는 스크립트 언어를 위해 만들어진 문자 기반의 프로토콜
  • WebSocket은 기존의 http와는 다르게 Line Header Body의 구조가 없이 메시지만 전달되는 구조이므로 전달 시 규약을 개발자가 구현해야 함
  • stomp는 command subscribe send의 전송 구조를 갖기 때문에 개발자가 규약을 정할 필요가 없으며, 전송에 관련된 양 피어가 독립적으로 동작할 수 있는 구조를 가짐
  • subscribe => 보내는 사람은 발행자, 받는 사람이 구독자의 개념 => 카테고리를 결정한다는 것은 어떤 구독자에게 보낼 것인가!!! (채팅방의 개념으로 접근)

frame 종류 #

  • CONNECT : STOMP 클라이언트가 연결을 수립하고 스트림을 초기화할 때 사용.
  • CONNECTED : 클라이언트의 연결 시도를 서버가 수락하면 사용되는 프레임.
  • SUBSCRIBE : destination을 대상으로 전송되는 메시지를 청취하기 위해 사용.
  • UNSUBSCRIBE : destionation 을 대상으로 한 구독을 취소하기 위해 사용.
  • SEND (body) : 클라이언트가 destination을 대상으로 메시지를 전송하기 위해 사용.
  • BEGIN (transaction): 트랜잭션의 시작을 의미하는 프레임
  • COMMIT (transaction) : 트랜잭션 커밋 프레임
  • ABORT (transaction) : 트랜잭션 롤백 프레임
  • DISCONNECT : 연결 종료 프레임.
  • MESSAGE (body) : 브로커에서 릴레이 된 구독 메시지가 전송될 때 사용되는 프레임.
  • RECEIPT : 클라이언트가 보낸 프레임을 서버가 처리 완료하면, 전송되는 프레임.
  • ERROR (body) : 에러 발생시 전송되는 프레임

메시지 중계 구조 #

  • 스프링 빌트인 메시지 브로커를 사용하는 3개의 메시지 채널
  • clientInboundChannel : 웹 소켓 클라이언트로부터 수신할 메시지 채널
  • clientOutboundChannel : 웹 소켓 클라이언트에게 메시지를 송신할 채널
  • brokerChannel : 애플리케이션 내에서 메시지 브로커에게 메시지를 송신할 채널
  • STOMP 메시지 브로커로 연결하기 위해 클라이언트는 CONNECT 프레임을 전송하고, 수락되면 브로커에서 클라이언트로 CONNECTED 프레임이 전송 (연결 종료를 위해 DISCONNETCT 프레임이 전송되면, 서버에서는 이를 확인했다는 의미로 RECEIPT 프레임이 전송되고 소켓은 종료)
  • 클라이언트는 SUBSCRIBE 프레임으로 구독하고자 하는 메시지의 카테고리를 결정하는데, 이때 하나의 구독에 대해 id가 부여되고, 구독 메시지의 카테고리는 destination 헤더로 표현
  • 클라이언트는 SEND 프레임을 사용하여 메시지를 보내고, 서버에서는 MESSAGE 프레임으로 모든 구독자에게 브로드캐스팅 할 수 있음(이때 서버는 subscription 헤더를 통해 하나의 구독자를 표현하고, desination 헤더로 메시지의 카테고리를 표현)
0.0.1_20210630_7_v33