웹소켓
#
Find similar titles
Structured data
- Category
- Programming
Table of Contents
웹 소켓 #
웹 소켓 이란? #
- 대부분의 웹 기반 클라이언트-서버 애플리케이션에서 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 헤더로 메시지의 카테고리를 표현)