웹 소켓(WebSocket)
: 서버와 클라이언트 간에 양방향 통신을 가능하게 해주는 프로토콜
- 양방향 통신
- 데이터 송수신을 동시에 할 수 있다.
- 클라이언트(Client)와 서버(Server)가 서로 원할때 데이터를 주고 받는다.
- 연결지향
- 서버와 클라이언트 간에 지속적인 연결을 유지하고, 양방향으로 데이터를 실시간으로 주고받을 수 있도록 한다.
- 서버가 클라이언트에게 데이터를 푸시(push) 할 수 있으며, 클라이언트도 서버에 데이터를 보낼 수 있다.
- 상태 유지
- 웹 소켓은 연결을 지속적으로 유지하므로, 클라이언트의 상태 정보를 서버가 유지할 수 있다.
- 실시간 네트워킹
- 웹화면에서 연속된 데이터를 빠르게 노출
- ex) 채팅, 알림, 실시간 게임, 주식 등
- 여러 단말기에 빠르게 데이터 교환
- 웹화면에서 연속된 데이터를 빠르게 노출
웹 소켓을 구현하기 위해서는 웹 서버와 클라이언트 양쪽 모두에서 웹 소켓 프로토콜을 지원해야 한다.
대부분의 최신 웹 브라우저에서 웹 소켓을 지원하며, 서버 측은 Spring WebSocket, Node.js의 ws 모듈 등 다양한 라이브러리를 사용해 웹 소켓을 구현할 수 있다.
웹 소켓을 사용하면 실시간 기능을 구현하는데 도움이 된다.
HTTP
기존의 HTTP 프로토콜은 다음과 같은 특성을 가진다.
1. 단방향 통신
- 클라이언트-서버 구조클라이언트는 서버에 요청을 보내고 대기. 서버는 요청 결과를 만들어서 응답을 준다.
2. 비연결성(Connectless)
- 클라이언트가 서버에 요청을 하고 응답을 받으면 바로 TCP/IP 연결을 끊어 연결을 유지 하지 않는다.
- 이를 통해 서버의 자원을 효율적으로 관리하고, 수 많은 클라이언트의 요청에도 대응할 수 있다.
- 웹 애플리케이션에서 서버로부터 실시간 데이터를 주기적으로 가져오기 위해 주기적으로 요청을 보내야 하는 번거로움을 가진다.
3. 무상태(Stateless)
: 서버가 클라이언트의 이전 상태를 보존하지 않는다.
동작 원리
- 영역
- 연결 설정(Opening Handshake)
- 데이터 전송(Data Transfer)
- 연결 해제(Closing Handshake)
Handshake
- 클라이언트가 서버에 웹 소켓 연결을 요청한다.
-> 이 요청은 HTTP 프로토콜을 통해 이루어진다.
- 서버는 클라이언트의 요청을 받아들이고 ,웹 소켓 연결을 위해 HTTP Upgrade 요청을 보낸다.
- 클라이언트는 서버의 Upgrade 요청을 받아들이고, 연결을 웹 소켓 프로토콜로 업그레이드한다.
이러한 핸드쉐이크 과정을 거쳐 웹 소켓 연결이 수립된다.
연결 설정(Opening Handshake)
: 연결 수립 요청하는 헤더
- 클라이언트가 서버에 웹 소켓 연결을 요청한다.
- 이 요청은 HTTP 프로토콜로 이루어진다.
- 클라이언트는 웹 소켓 연결을 설정하기 위해 "Upgrade" 헤더와 "Connection" 헤더를 포함한 HTTP 요청을 보낸다.
- HTTP 1.1 이상이어야 한다.
- Upgrade
- 현재 프로토콜(protocol)에서 다른 프로토콜 업그레이드 또는 변경 할때 사용한다.
- websocket으로 변경해준다.
- 이 값이 없거나 다른 값이면 cross-protocol attack이라고 간주하여 접속을 중지시킨다.
- Connection
- 현재의 전송 완료 후 network를 유지할 것인지에 대한 정보를 나타낸다.
- 웹소켓 요청시 upgrade라는 값을 가진다.
- 이 값이 없거나 다른값이면 웹 소켓 연결 중지
- Sec-WebSocket-Key: 유효한 요청인지 확인하기 위해 사용하는 키 값
- Sec-WebSocket-Protocol: 사용하고자 하는 하나 이상의 웹 소켓 프로토콜 지정
- 필요한 경우에만 사용한다.
- Origin
- 모든 브라우저는 보안을 위해 이 헤더를 보낸다. (Cross-Site WebSocket Hijacking와 같은 공격을 피하기 위해서)
- 대부분 애플리케이션은 이 헤더가 없는 요청을 거부하며, 이러한 이유로 CORS 정책이 만들어졌다.
- 서버는 클라이언트의 웹 소켓 연결 요청을 받아들이고, 클라이언트의 요청에 대해 "101 Switching Protocols" 응답을 보낸다.
- 이 응답은 HTTP 프로토콜에서 웹 소켓 프로토콜로의 업그레이드를 수락한다는 의미이다.
- 101은 '프로토콜 전환'을 서버가 승인했음을 알리는 코드이다.
- UPgrade와 Connection은 동일하게 넣어줘야 한다.
- Sec-WebSocket-Key에 유니크 아이디를 더해 SHA-1로 해싱한 후, base64로 인코딩한 결과
- 웹소켓 연결이 개시되었음을 알려줌과 동시에 클라이언트에서 계산한 값과 일치하지 않으면 요청 수립하지 않는다.
이후부터는 클라이언트와 서버 간의 연결은 웹 소켓 프로토콜로 이루어진다.
데이터 전송(Data Transfer)
- 웹 소켓 연결수립이 완료되면 클라이언트와 서버는 양방향으로 데이터를 주고받을 수 있다.
- 클라이언트와 서버가 메시지(message)라는 개념으로 데이터를 주고 받는다.
- 클라이언트나 서버는 웹 소켓 연결을 통해 데이터를 주고받을 때, 프레임(frame)이라고 하는 작은 패킷으로 데이터를 전송한다.
- 프레임은 하나 이상의 메시지로 구성될 수 있으며, 이 메시지는 텍스트 또는 바이너리 형태의 데이터를 포함할 수 있다.
- 데이터가 프레임으로 캡슐화되어 전송되기 때문에, 클라이언트와 서버는 실시간으로 데이터를 주고받을 수 있다.
- Handshake가 끝난 시점부터 서버와 클라이언트는 서로가 살아 있는지 확인하가 위해 heartbeat 패킷을 보내며, 주기적으로 Ping을 보내 체크한다.
연결 해제(Close Handshake)
- 웹 소켓 연결을 더 이상 유지할 필요가 없을 때, 클라이언트나 서버는 연결을 닫을 수 있다.
- 클라이언트나 서버가 연결(Connection) 종료를 위한 컨트롤 프레임을 전송한다.
- 컨트롤 프레임은 closing handshake를 시작하라는 데이터를 내포하고 있다.
- 이에 대한 응답으로 Close 프레임이 전송된다.
- 이 프레임에는 연결을 닫는 이ㅠㅇ에 대한 코드와 선택적인 메시지가 포함될 수 있다.
- 웹 소켓 연결이 종료된 이후 수신되는 모든 추가적인 데이터는 버려진다.
[주의] 웹소켓 지원 현황
HTML5 이후에 나왔기 때문에 모든 환경에서 웹 소켓을 지원하지 않는다.
SocketJS와 Socket.io
SocketJS, Socket.io 라이브러리를 사용하면 웹 소켓을 지원하지 않는 브라우저에서도 웹 소켓을 사용하는 것과 비슷하게 사용할 수 있다. 이 라이브러리들이 요청을 보내는 브라우저가 웹 소켓들을 제공하는지 확인 후 지원하지 않으면 해당 라이브러리를 사용해 웹소켓을 사용하는 것처럼 보여지게 된다.
한계
- 문자열만 주고 받는다.
- 문자열 해독을 애플리케이션에 맡긴다.
- 브라우저 호환성
- 웹 소켓은 최신 웹 브라우저에서는 잘 지원되지만, 구형 브라우저에서는 웹 소켓을 지원하지 않을 수 있다.
- 네트워크 제한
- 웹 소켓은 기본적으로 TCP 기반의 프로토콜을 사용하기에, 일부 네트워크 환경에서는 웹 소켓 연결이 차단되거나 제한될 수 있다.
- 서버 부하
- 웹 소켓은 지속적인 연결을 유지하므로, 많은 클라이언트와의 동시 연결로 인해 서버 부하가 증가할 수 있다.
- 보안
- 웹 소켓은 서버와 클라이언트 간에 지속적인 연결을 필요로 하기에 보안 측면에서 추가적인 주의가 필요하다.
- 프로토콜 복잡성
- HTTP의 경우 형식을 정해 놓아 모두가 따르기만 하면 해석이 쉽지만 웹 소켓(WebSocket)은 형식이 정해져 있지 않아 애플리케이션에서 해독이 어렵다.
Spring Sockets
WebSocket
SocketJS
STOMP(Streaming Text Oriented Messaging Protocol): 토픽 구독방식
- 웹 소켓과 함께 사용되는 메시징 프로토콜이다.
- 웹 소켓의 단순한 기능을 확장하여 메시지 전달과 구독을 더욱 편리하게 만들어준다.
- STOMP를 사용하면 클라이언트와 서버 간의 메시지 전달 및 구독을 쉽게 구현할 수 있으며, 주로 메시지 브로커(Message Broker)와 함께 사용하여 실시간 메시지 전달을 처리하는 데 유용하다.
구성 요소
- WebSocketHandler
: 클라이언트로부터 메시지를 수신하고, 클라이언트에게 메시지를 보낼 때 사용되는 핸들러 - WebSocketSession
: 서버와 클라이언트 간의 연결을 나타내는 객체로, WebSocketHandler를 통해 데이터를 주고받을 수 있다. - WebSocketConfigure
: Spring의 구성 클래스로, 웹 소켓 연결에 대한 구성을 담당한다.
참고
- 시니어코딩 - Spring Sockets 유튜브 강의
- Github