HTTP는 Stateless, Connectionless의 특징을 지니기 때문에 통상적인 Http 통신은 클라이언트가 요청을 보내는 경우에만 Server가 응답할 수 있다. (단방향 통신)
- 하지만 웹 개발을 하다보면 두 프로그램 간의 메시지를 교환해야하는 양방향 통신 혹은 실시간으로 데이터 처리가 필요한 경우가 있다. (채팅, 주식, 비디오 데이터) 통신기술의 종류를 알아보자
실시간 통신 기술 종류 (http 프로토콜)
Polling
Real-time 통신에서는 언제 통신이 발생할지 예측이 불가능하여 클라이언트가 일정 주기로 request를 서버로 계속 보내서 이벤트 내용을 전달받는 방식이다.
- 클라이언트가 많아지면 서버의 부담이 급증하게 된다.
- request connection을 맺고 끊는것에도 자원이 들어가는데 불필요한 request와 connection이 생성된다.
- 클라이언트에서 실시간정도의 빠른 응답을 기대하기 어렵다. (Real-time 통신이라고 부르기 애매할 정도의 실시간성)
Long Polling
클라이언트에서 서버로 request를 보내고 기다리다가 서버에서 해당 클라이언트로 이벤트가 생겨 response가 오면 연결이 종료된다. 이 후 클라이언트에서는 곧바로 다시 request를 보내서 서버의 다음 이벤트를 기다리는 방식이다.
- polling 방식보다는 서버의 부담이 줄겠지만 클라이언트로 보내는 이벤트들의 시간간격이 좁아서 메세지가 쏟아질 경우 polling 방식과 같아지게 된다.
- 서버에서 클라이언트에게 응답을 보내면 곧바로 요청이 들어오기 때문에 다수의 클라이언트 요청을 처리하더라도 곧바로 다수의 클라이언트가 서버로 connection을 요청하면서 서버의 부담이 급증하게 된다.
Server-Sent Events (SSE)
long polling과 유사하게 요청을 하기 위해서 클라이언트에서 서버로 request를 보내고 서버에 이벤트를 기다리지만 서버에서 이벤트를 응답할 때 해당 요청을 끊지 않고 필요한 메시지만 보내기를(flush) 반복하는 방식이다.
- 서버에서 이벤트가 발생할 때마다 실시간으로 메시지를 보낼 수 있기 때문에 실시간성이 훨씬 뛰어나다.
- long polling과 다르게 서버에서 메시지를 보내고 다시 connection을 연결을 하지 않아도 되기 때문에 부담이 줄어드는 장점이 있다.
- 연결 시간이 길어질 수록 연결 유효성 관리의 부담이 발생한다. (많은 클라이언트 동시 연결 부담도...)
- GET 메소드만 지원하고, 파라미터를 보내는데 한계가 있다.
- 클라이언트가 페이지를 닫아도 서버에서 감지하기가 어렵다는것도 단점이다.
long polling, streaming 방식의 경우 서버에서 클라이언트로 메시지를 보낼 수 는 있으나 클라이언트에서 서버로 메시지를 보내지 못하는것에 가깝다. (서버 ➡️ 클라이언트 단방향 통신)
위의 세 방식 모두 HTTP를 통해 통신하기 때문에 Request/Response 모두 헤더가 불필요하게 크다는 문제가 있다.
Server sent events가 web socket에 비교했을 때 이점
- 새로운 프로토콜을 익힐 필요가 없다. (Websocket 프로토콜과 다르게 http 프로토콜)
- http 프로토콜에서 헤더에 이벤트의 미디어 타입 표준으로 "Content-Type: text/event-stream;charset=UTF-8" , 이벤트는 캐싱하지 않으며 지속적 연결을 사용해야 하기 때문에 "Cache-Control: no-cache" 설정하기 (참고글)
- 서버측에서의 단방향 통신을 지원하기 때문에 양방향으로 통신하는 웹소켓 보다 비용쪽에서 우월하다.
- Spring에서 SseEmitter객체를 사용하면 구현가능 하다. (WebFlux, MVC구현 튜토리얼)
WebSocket
클라이언트 서버간 양방향 통신이 가능하게 하기 위해서 HTML5 표준의 일부로 webSocket이 만들어지게 되었다.
- 클라이언트-서버 간의 하나의 Socket Connection을 유지해서 언제든 자유롭게 양방향 통신 가능
- 접속을 위해서는 HTTP를 사용하지만 이후 통신은 WebSocket 독자 프로토콜이 사용된다.
- 프레임으로 구성된 메시지라는 논리적 단위로 송수신한다. (UTF-8 인코딩만 지원)
- 메시지에 포함될 수 있는 교환 가능한 메시지는 텍스트와 바이너리이다.
WebSocket 동작 과정
- handshaking으로 HTTP 요청을 사용해 서버와 클라이언트 간의 연결이 이루어짐
- 서버와 클라이언튼 간의 웹소켓 연결이 정상적으로 이루어 진다면 일정 시간 이후 HTTP 연결은 자동으로 끊어짐
- 이후 ws(80), wss(443) 프로토콜을 통해 양방향 통신
Handshake
Opening Handshake 와 Closing Handshake 는 일반적인 HTTP TCP 통신의 과정 중 하나이다.
접속 요청은 HTTP 로 한 뒤, 웹소켓 프로토콜로 변경된다.
- 'http://' 와 다르게 'ws://' 와 같은 Web Socket Structure를 사용한다.
요청(Request) 헤더
웹소켓 프로토콜로 변경되기 위한 HTTP 헤더는 아래처럼 구성되어 있다.
GET /chat HTTP/1.1
Host: localhost:8080
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://localhost:9000
GET /chat HTTP/1.1
웹소켓의 통신 요청에서 HTTP 버전은 1.1 이상이어야하고 GET 메서드를 사용해야햔다.
Upgrade
프로토콜을 전환하기 위해 사용하는 헤더로 웹소켓 요청시에는 websocket 이라는 값을 가진다.
- 이 값이 없거나 다른 값이면 cross-protocol attack 이라고 간주하여 웹 소켓 접속을 중지시킨다.
Connection
현재의 전송이 완료된 후 네트워크 접속을 유지할 것인가에 대한 정보로 웹 소켓 요청 시에는 반드시 Upgrade 라는 값을 가진다.
- Upgrade 와 마찬가지로 이 값이 없거나 다른 값이면 웹소켓 접속을 중지시킨다.
Sec-WebSocket-Key
유효한 요청인지 확인하기 위해 사용하는 키 값이다.
- 길이가 16바이트인 임의로 선택된 숫자를 base64로 인코딩 한 값
Sec-WebSocket-Protocol
사용하고자 하는 하나 이상의 웹 소켓 프로토콜 지정한다. (필요한 경우에만 사용)
Sec-WebSocket-Version
클라이언트가 사용하고자 하는 웹소켓 프로토콜 버전이다.
Origin
CORS 정책으로 만들어진 헤더로 Cross-Site Websocket Hijacking과 같은 공격을 피하기 위함이다. (클라이언트 주소)
응답(Response) 헤더
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
HTTP/1.1 101 Switching Protocols
101은 HTTP에서 WS로 프로토콜 전환이 승인 되었다는 응답코드이다.
Sec-WebSocket-Accept
요청 헤더의 Sec-WebSocket-Key에 유니크 아이디를 더해서 SHA-1로 해싱한 후 base64로 인코딩한 결과로 웹 소켓 연결이 개시되었음을 알린다.
Data Transfer
Opening HandShake에서 승인이 나고나면, 웹 소켓 프로토콜로 Data transfer 이 진행된다. (데이터는 메시지라는 단위로 전달)
메시지
여러 프레임(frame)이 모여서 구성되는 하나의 논리적인 메시지 단위로 웹소켓 통신에 사용되는 데이터는 UTF-8 인코딩을 통해서만 지원이 된다.
- ex) "0x00 (보내고 싶은 데이터) 0xff"
프레임
프레임은 데이터 링크계층(이더넷)에서 주고 받는 가장 작은 단위의 데이터로 (패킷은 전 네트워크 통신 과정에서 가장 작은 단위의 데이터)
작은 헤더 + paylocad로 구성되었다.
- http 통신의 단점(헤더정보가 불필요하게 크다는 문제)를 해결하기 위해서 작은 헤더를 사용한다.
Socket.io
웹소켓은 HTML5의 기술이기 때문에 구버전 사용자들은 WebSocket으로 작성된 웹 페이지를 볼 수가 없는 문제를 해결하기 위해 Socket.io가 나오게 되었다. (클라이언트, 브라우저에 구애받지 않고 실시간 통신 가능)
- 웹페이지가 열리는 브라우저가 webSocket을 지원하면 일반 webSocket 방식으로 동작하고 지원하지 않는 브라우저라면 위에서 설명한 일반 http 스팩을 이용해서 실시간통신을 흉내낼수 있는 방식으로 통신을 하게 해준다.
양방향 통신을 하기 위해 웹 소켓 기술을 활용하는 Node.js 라이브러리로 javascript 기반 솔루션인 만큼 javascript로 개발해야 문제발생을 줄일 수 있겠지만 자바로 개발이 가능하다.
참고
WebSocket VS Server-Sent Events
WebSocket VS Server-Sent Events
johnie.dev
polling, long polling, webSocket, socket.io
* webSocket과 socket io의 차이점브라우저 지원이 socket io가 훨씬 많음.(특히 webBrowser는 webSocket 지원 안함) 기존의 양방향 통신 방법webSocket은 웹페이지와 서버간에 실시간 상호작용을 위해 만들어진
rubberduck-debug.tistory.com
Server-Sent Events를 이용한 비동기 통신 구현 및 트러블슈팅
SSE 통신 구현 및 관련 트러블슈팅 경험을 공유합니다.
gong-check.github.io
WebSocket이란? 개념과 동작 과정 (+socket.io, Polling, Streaming...)
📢 들어가며 직장에서 자동 업데이트 기능을 구현할 일이 생겼다. 누군가 웹의 데이터를 수정했을 때 다른 PC를 사용 중인 사람의 화면에도 해당 데이터가 자동으로 실시간 업데이트 되게하는
doozi0316.tistory.com
'Web' 카테고리의 다른 글
Stateful과 Stateless + Connectionless (1) | 2024.01.15 |
---|---|
OAuth2(Open Authorization) (0) | 2023.04.08 |
Redis(Remote Dictionary Server) (0) | 2023.03.30 |
JWT(Json Web Token) (0) | 2023.03.23 |
HTTP 메소드 (0) | 2022.12.29 |