HTTP 1.1 이하에서는 클라이언트가 서버에게 요청을 보내고 응답을 하는 단방향 소통이다. 일반적인 기능은 이런 단방향 뱡식으로 구현이 가능하지만 다른 방식이 필요할 때가 있다.
예를 들어 채팅 기능이 있다. 채팅 기능에서 HTTP의 단방향 소통의 문제점은 상대방이 메세지를 보냈을때 사용자가 알아채기 어렵다는 것이다. 이는 서버는 클라이언트의 요청이 없이 응답을 보낼 수 없기 때문이다.
이를 해결하기 위해 사용된 것이 HTTP의 Polling 이다
이는 클라이언트가 주기적으로 서버에 요청을 보내 확인하는 것이다.
Polling의 문제점에는 요청을 보내는 주기 만큼 지연이 발생한다, 불필요한 요청들 주기적으로 발생하고 이는 곧 트래픽의 낭비를 야기한다.
이를 해결하기 위해 Long Polling,
서버가 클라이언트의 요청에 바로 응답하지 않고 업데이트가 발생할 때까지 기다렸다가 데이터가 업데이트되거나 타임아웃 시간이 지나면 응답을 보내는 것이다.
이는 업데이트 반응 속도는 빨라지게 하지만 서버의 부담이 커지고 이는 다시 업데이트에 대한 반응이 느려지는 악순환을 만든다.
그렇게 나온 것이 클라이언트와 서버가 동등하게 메세지를 주고 받을 수 있는 양방향 통신을 위한 웹소켓이다.
gRPC에서 사용되는 양방향 통신인 HTTP2와 다른 점은 무엇일까 ?
HTTP2도 양반향 통신이 가능하지만 이는 장시간 양방향 통신을 위해 설계된 것이 아니다.
또한 HTTP 2에서 서버 쪽에서 바로 직전에 요청이 없이 응답을 보내는 것이 가능하지만 이는 클라이언트의 초기 요청에 대한 응답의 일부로 보내는 것으로 클라이언트의 초기 요청이 없다고 응답을 할 수 없다. 그렇기 때문에 연결의 지속을 위해서 주기적인 요청이 필요하다.
연결 : 클라이언트는 웹소켓 연결 요청을 HTTP를 통해 서버에 보낸다.
서버는 또한 가능한 경우 수락하는 응답을 HTTP로 보낸다
→ 이과 같은 과정을 Handshake라 한다. 이때부터 클라이언트와 서버는 HTTP가 아닌 웹소켓 프로토콜을 사용하여 소통하게 된다.
통신 :클라이언트와 서버는 자유롭게 메세지 보내며 통신한다. 웹소켓은 헤더의 크기가 작고 오버헤드가 작아 HTTP보다 효율적인 통신이 가능하다.
종료 : 한쪽이 종료 요청 CLOSE 프레임을 보내면 다른 한쪽에서도 동일한 CLOSE 프레임을 보내고 연결이 종료된다. 비정상적인 종료를 대비하기 위하여 지정된 시간동안 메세지가 없을 경우 확인 패킷을 보내거나 주기적으로 ping pong 프레임을 주고 받아서 접속을 확인할 수 있다.
Handshake 과정을 더 자세히 알아보자.

클라이언트에서 현재의 HTTP 연결을 웹소켓 프로토콜로 업그레이드하자는 내용의 헤더를 전송한다.

헤더 안에는 sec-Websocket-Key가 있다. 이는 클라이언트가 랜덤으로 생성한 값을 Base 64로 인코딩한 값을 담고 있다.

서버는 요청을 받고 나서 sec-Websocket-Key의 값을 guid라 불리는 정해진 문자열을 그 키에 이어붙인 뒤 sha-1 해시로 계산하여 다시 Base 64로 인코딩하여 클라이언트에서 전달한다.
즉, 전달 받은 값으로 해석할 수 있는 비밀 키를 다시 전달한다.

클라이언트는 전달 받은 값을 해석하여 자신이 보낸 키로부터 파생된 값인지 확인하고 맞다면 보낸 양방향 소통을 하게 된다.

그럼 TCP UDP 소켓과 웹소켓은 무엇이 다를까 ?
이들은 속한 OSI 계층이 다르다.
TCP UDP 소켓 - 4계층 = 전송 계층
웹소켓 - 7계층 = 응용 계층
웹소켓은 TCP 소켓을 기반으로 동작한다. 이는 즉, 웹소켓에서의 통신은 TCP를 기반으로 작동하기 때문에 데이터의 순서와 신뢰가 보장된다는 것을 의미한다.
이 같은 장점으로 웹소켓은 채팅 뿐만 아니라 온라인 게임, 주식 관련 앱, 위치 추적 등 실시간 양방향 통신이 필요한 수많은 분야에 활용된다.
서버의 설계에 따라 구현이 복잡해진다. 특히 로드 밸런싱이 적용된 서버에서는 이를 위해 고려하고 설정할 부분이 많아진다.

로드 밸런싱 - 서버 여러 대가 클라이언트 요청을 나눠서 처리하는 것
웹소켓은 특정 서버와의 지속적인 연결 안에 이뤄지기 때문에 한 서버와 웹 소켓 통신을 시작하면 이후로도 계속 그 서버로만 데이터가 전송되도록 설정해야한다. 이를 해결하기 위하여 웹 소켓을 처리할 수 있는 로드 밸런서를 선택하여 구성하는 방법이 있다.
따라서 대용량 데이터의 경우 분할 전송하거나, 다른 프로토콜 사용들의 방법을 사용할 수 있다.
일부 오래된 브라우저나 네트워크 환경에서는 웹소켓이 제대로 동작하지 않을 수 있다. 이를 해결하기 위해 폴백(fallback) 방식(Long Polling,XHR Polling 등)을 사용할 수 있다. 이렇게 폴백 방법을 사용하면 웹소켓을 지원하지 않는 환경에서도 실시간 통신을 유지할 수 있다.
마지막으로, 웹소켓의 기본 프로토콜인 WS는 통신이 암호화되어 있지 않다. 그렇기 때문에 보안이 중요한 서비스라면 SSL/TLS 인증서를 발급 받은 뒤 이를 사용하여 WSS를 설정해야 한다.
POLLING 등의 방식보다는 훨씬 덜하지만 웹소켓도 서버에 부담을 주는 건 마찬가지이다.
많은 사용자들이 동시 접속의 경우 유지해야 하는 TCP연결이 많아지고 메세지들이 빈도가 높아진다면 CPU 사용량도 증가한다. 따라서 무조건 웹소켓을 사용할 것이 아니라 구현할 서비스에 적절한 선택인지 고려, 선택해야 한다.
‘얄팍한 코딩사전 - **웹소켓을 알아봅시다.’를 참고, 정리하였습니다.