WebSocket 기본 개념과 HandShake

WebSocket 도입 이유
데이터가 꾸준히/지속적으로 업데이트 되는 경우 WebSocket이 아니라면?
- 유저가 데이터를 달라고 계속 요청
- UX가 느리고 불편함
- 실시간 성과 거리가 멈(변화가 있어도 사용자는 모름)
- 비효율적인 사용자 동작필요
- Polling: 클라이언트(프론트)가 데이터를 달라고 주기적으로 요청
- 불필요한 요청 증가 -> 서버 리소스 낭비
- 실시간성 한계 -> 간격 사이에 변경된 데이터는 사용자가 늦게 받음
- 빈번한 요청이 많은 유저 수에서 성능 이슈 유발
- Long Polling: 클라이언트가 서버에 요청을 보내면 서버는 새로운 데이터가 발생할때 까지 응답을 지연, 데이터가 준비되면 서버가 즉시 응답을 전송하고, 클라이언트는 응답을 받은 후, 다시 새로운 요청을 보냄
- 어느 정도 실시간성 확보 가능
- 하지만 요청-응답 방식이라 HTTP 커넥션을 반복적으로 재연결해야함
- 연결 수가 많아지면 서버 부담 증가
- SSE: 서버가 클라이언트에게 단방향으로 실시간 데이터 푸시
- HTTP 기반이라 브라우저 지원이 안정적이고 구현도 간단
- 하지만..
- 단방향 통신만 가능 (서버 -> 클라이언트)
- 브라우저/네트워크 상황에 따라 자동 재연결 불안정
- HTTP/2 미지원, 제한적인 헤더 처리 등으로 제약이 있음
- 모바일 환경에서 백그라운드 처리 어려움
그럼 WebSocket은?
- 클라이언트와 서버 간의 연결을 한 번 맺으면, 그 이후로는 지속적인 연결상태에서 실시간으로 데이터를 주고 받을 수 있음
- 양방향 통신 지원 -> 클라이언트도 서버에, 서버도 클라이언트에 필요시 즉시 메시지 전송 가능
- HTTP 기반
Handshake 이후 WebSocket 프로토콜로 업그레이드 되며, 이후엔 오버헤드 없이 가볍고 빠르게 메시지를 주고 받음
단점도 있을까?
- 클라이언트에서 지원을 해주니까 가능, 브라우저 중 버전에 따라 지원을 안하는 경우도 있음(최근에는 거의 없음)
- Stateful
- WebSocket은 Stateless를 지향하는 일반 HTTP(REST)와는 다르게 상태를 유지하는 Stateful한 성격을 가지고 있음(서버와 클라이언트가 연결을 항상 유지해야됨)
- 연결을 유지해야 하기 때문에 부하가 발생 할 수 있고, 비정상적으로 연결이 끊어졋을 때 적절한 대응이 필요
WebSocket HandShake

- 헨드쉐이크 요청(HTTP Upgrade Request): WebSocket 프로토콜로 전환
- 클라이언트는 일반 HTTP GET 요청을 보내면서 Upgrade: websocket, Connection: Upgrade, Sec-WebSocket-Key 등의 헤더를 포함합니다.
- 핸드쉐이크 요청 수신(Request Reception)
- 서버는 클라이언트의 HTTP GET 요청을 받고, Upgrade및 관련 헤더를 확인합니다.
- 요청이 WebSocket 연결 요청임을 인지하고, 프로토콜 전환을 위한 준비를 시작합니다.
- 핸드쉐이크 응답 전송(HTTP 101 response)
- 서버는 클라이언트가 보낸 Sec-WebSocket-Key를 기반으로 계산된 값을 포함한 HTTP 101 Switching Protocols 응답을 전송함
- 핸드쉐이크 응답 수신(Response Reception)
- 서버가 HTTP 101 Switching Protocols 응답을 보내면, 클라이언트는 WebSocket 연결이 성공적으로 확립되었음을 확인함
- 응답 헤더에는 서버가 생성한 Sec-WebSocket-Accpet 값이 포함되어 있어, 요청의 유효성을 검증함
- 데이터 전송 및 수신(Data Exchange)
- 클라이언트
- WebSocket 프레임 단위로 메시지를 전송
- 서버로부터의 응답 역시 동일한 방식으로 프레임 단위로 수신되며, 이로써 양방향 통신이 가능해짐
- 서버
- 클라이언트로부터 전송된 WebSocket 프레임을 받아 내부 로직 처리 결과를 WebSocket 프레임으로 클라이언트에 다시 전송
- 공통으로
- 필요에 따라 ping/pong 프레임을 주고 받으며 연결 상태를 확인 할 수 있음
- 연결 종료(Close)
- 클라이언트 또는 서버가 close 프레임을 보내어 연결 종료를 요청하면, 상대측은 종료 절차를 수행한 후. 연결이 종료됨
WebSocket을 구현하려면
- 라이브러리 / 브라우저에서 지원
- 핸드셰이크 요청 수신
- 핸드셰이크 응답 전송
- 데이터 처리 및 전송
- 연결 종료 처리
- 개발자가 해야할 일
- 데이터 처리
- 세션 관리
- 각 이벤트마다 추가로 처리할 일