[프로젝트] 웹소켓으로 채팅 구현하기 #1. WebSocket의 이해

bien·2024년 8월 12일
15

LegendsOfLeague

목록 보기
4/4

WebSocket 이란?

WebSockets are a powerful communication protocol that enables bidirectional, real-time communication between a client and a server over a single TCP connection

WebSocket은 클라이언트와 서버 간에 단일 TCP 연결을 통해 양방향 실시간 통신이 가능하게 하는 강력한 통신 프로토콜이다. 웹 소켓은 전통적인 API 프로토콜보다 빠르고 요구되는 오버헤드가 적은 "실시간" 애플리케이션 개발이 가능하도록 한다. 웹 소켓은 서버와 클라이언트간의 통신에 이중(duplex) 프로토콜을 사용한다.

  • overhead(오버헤드): 어떤 처리를 하기 위해 들어가는 간접적인 처리 시간 · 메모리

웹소켓의 특징

  • 웹 소켓은 본질적으로 양방향이다. (Web-sockets are bi-directional in nature)
  • 웹 소켓을 사용하여 개발된 연결은 참가자(클라이언트 또는 서버) 중 하나가 연결을 종료하기 전까지 지속된다.
  • 웹 소켓은 HTTP를 사용하여 연결을 시작한다.

왜 사용할까?

실시간 환경이 요구되는 시스템에서 WebSocket은 쉽고 신뢰할 수 있는 요긴한 해결책이다. 계속 변하는 데이터를 실시간으로 보여줘야하는 애플리케이션을 개발하는 경우, WebSocket의 구현을 고려할 수 있다. 다른 방법도 있지만, 이들은 서버에 오버헤드를 증가시키므로 결국 당신은 웹 소켓을 고려하게 될 것이다.

웹 소켓의 일반적 사용 사례

  • 증권거래소(종목 가격, 주문장 등 실시간 업데이트)
  • 채팅 어플리케이션 (메시지 주고받기가 빨라야 하므로)
  • 실시간 변경이 필요한 웹 애플리케이션
  • 게임 산업

어떻게 작동할까?

웹 소켓은 클라이언트와 서버간의 연결을 생성해 작동한다. 연결을 시작하기 위해 클라이언트 측에서 update 헤더가 포함된 Get 요청을 전송한다. 이를 통해 서버는 해당 요청이 업그레이드 요청임을 인식하고, 서버가 업그레이드 속성을 지원하는 경우 상태코드 101 Switching Protocols을 반환하고, 업그레이드 속성을 지원하지 않는 경우 에러 코드를 반환한다. 만약 101이 아닌 다른 상태코드가 반환되는 경우, 클라이언트 측에서 연결을 종료한다.

웹 소켓은 클라이언트와 서버간의 단일 연결을 생성하고, 그들이 가지는 모든 의사소통에 대해 핸드셰이크(handshakes)를 생성하려고 요구되는 오버헤드가 없다.

Request Headers (Client)

handshake 생성을 위한 요청 헤더는 임의의 순서로 전송될 수 있다.

  • http의 Get요청을 사용한다. (버전은 1.1 이상이어야 한다.)
  • Host: 클라이언트와 서버가 서로를 식별할 수 있도록 host 이름이 추가될 수 있다.
  • Sec-WebSocket-Protocol (OPTIONAL): 클라이언트가 사용할 프로토콜을 지정하기 위해 클라이언트로부터 전송된다.
  • Sec-WebSocket-Version (OPTIONAL): 클라이언트가 허용하는 하위 프로토콜(웹소켓 프로토콜 위 애플리케이션 래밸에서 사용될 프로토콜)을 나타내기 위해 사용된다.
  • Origin: WebSocketAPI를 사용하는 스크립트에 의한 웹 브라우저의 무단 교차 출처 사용으로부터 WebSocket 서버를 보호하기 위해 사용된다. 서버는 허용된 origins 에서의 연결만을 허용한다.
  • Sec-WebSocket-Key: 무작위로 선택된 16바이트 값을 논스(nonce)로 사용해 생성된 base64 인코딩 된 값.

이러한 request를 받은 서버는 검증을 거친 후 handshake 요청을 수령 했으며 클라이언트가 연결을 생성할 수 있다는 답장을 반환해야 한다.

upgrade 헤더

  • 이미 설정된 클라이언트/서버 연결을 다른 포로토콜(동일한 전송 프로토콜을 통해)로 업그레이드 하는데 사용할 수 있는 표준 HTTP 헤더
    • 예를들어 클라이언트 연결을 HTTP 1.1에서 2.0으로 업그레이드 하거나 HTTP 또는 HTTPS 연결을 WebSocket으로 업그레이드 하는데 사용할 수 있다.
  • 클라이언트가 선호도 순서로 나열한 프로토콜 중 하나(또는 그 이상)을 선택해 전환하도록 서버를 초대하는데 사용될 수 있다.
    • 예시에서는 example/1, foo/2의 프로토콜을 요청했다.
  • 서버 측 response
    • 요청을 거절하는 경우: 헤더가 Upgrade로 전송되지 않은 것 처럼 (예: 200 OK) 응답한다.
    • 요청을 수락하는 경우.
      1. 전환되는 프로토콜을 Upgrade에 표기하고 101 Switching Protocols 상태를 반환한다.
      2. 새 프로토콜을 사용해 원래 요청에 대한 응답을 보낸다.
  • 주의: HTTP/2는 이 헤더의 사용을 명시적으로 금지한다. 이는 HTTP 1.1에만 해당된다.
    • HTTP/2 이상에서는 연결관련 지원 범위가 확장되어 Ugrade를 사용한 연결 업데이트 메커니즘이 필요하지 않은 것 같다. 따라서 헤당 헤더가 필수적이지 않지만, HTTP 1.1은 해당 헤더가 필요하므로 추가하는게 좋을 것 같다.
  • 구체적인 내용은 mdn 참조

Response Headers (Server)

서버가 수행하는 작업은 다음과 같다.

  • 핸드셰이크가 수신되었음을 증명하기 위해, 서버는 요청 헤더로부터 Sec-WebSocket-key 값을 가져와 전역 고유 식별자(Globally Unique Identifier)와 결합한 다음, 이 연결 문자열의 SHA-1 헤더를 생성한다.
  • 그런 다음 해당 문자열을 base64로 인코딩하여 서버 헨드셰이크로 변환한다.

  • HTTP/1.1 101 Switching Protocols: 서버는 101 상태 코드로 응답하며, 이외의 상태코드는 오류로 처리되어 핸드셰이크가 완료되지 않았음을 의미한다.
  • Connection & Upgrade: HTTP의 업그레이드를 의미한다.
  • Sec-WebSocket-Accept: 서버가 연결 요청을 수락했는지 여부를 나타낸다. 이 속성의 값은 Sec-WebSocket-keyGlobally Unique Identifie를 결합한 해시를 base64로 인코딩한 값을 가진다.
  • Sec-WebSocket-Protocol(OPTIONAL): 서버가 통신하기로 결정한 프로토콜을 의미한다.

WebSocket 클라이언트는 스크립트 페이지에서 이와 같은 응답의 속성값들을 확인한다. 만약 Sec-WebSocket-Accept 속성값이 예상한 값이 아니고, header filed가 누락되었거나, HTTP 상태코드가 1.1이 아닌경우 연결은 설정되지 않으며, WebSocket 프레임도 전송되지 않는다.

WebSocekt default URI format

ws를 위한 기본포트는 80이 사용되고 wss를 위한 기본 포트는 443이 사용되므로, 포트 구성 요소는 선택사항이다. wss는 보안 플래그가 설정되어 있고 서버와 클라이언트간 TLS 핸드 셰이크가 수행된 안전한 URI로 사용된다.


WebSocket Frames

웹소켓의 프레임(frame)은 클라이언트와 서버간 교환되는 기본적인 데이터 단위이다. 웹 소켓 프로토콜에서는 연속된 일련의 프레임을 통해 정보가 전달된다. 클라이언트는 프레임을 서버에 보내기 전에 마스크(mask)해야하며 마스크되지 않은 프레임이 서버에 수신되면 서버는 연결을 종료해야 한다.

이 경우, 서버는 1002(protocol error)와 함께 닫기(close) 프레임을 전송할 수 있다.

mask
WebSocket은 보안적인 측면에서 클라이언트의 악의적인 접근을 고려하고, 클라이언트의 브라우저만을 신뢰할 수 있는 상황에서도 네트워크 인프라와 서버를 보호해야 한다는 독특한 구조를 가진다. 마스킹 키는 브라우저에서 각 프레임마다 생성되며 무작위성을 가져 예측이 불가능하다. 이는 프락시 캐시 독점 공격(proxy cache poisoning attack)을 막기 위한 것이며, 악의적 사용자가 전송되는 바이트를 선택하는 것을 막아준다. 마스킹은 웹 소켓 통신 보안의 필수적 요소이며, 권장사항이 아니라 의무적으로 사용되어야 한다.

개념적으로 WebSocket은 아래 항목을 수행하는 TCP위 계층이다.

  • 웹의 origin 기반 브라우저 보안 정책을 추가한다.
  • 하나의 포트에서 다양한 서비스를 지원하고, 하나의 아이피 주소에 다양한 host를 지원하기 위한 주소지정(addressing), 프로토콜 명명 기전(protocol naming mechanism)을 추가한다.
  • TCP위에 프레이밍 매커니즘을 계층화하여 TCP가 구축된 IP 패킷 메커니즘 위에 작동하지만, 길이의 제한은 없다.
  • 프록시 및 기타 중개자가 있는 경우 작동하도록 설계된 대역 내 추가 폐쇄(close) 핸드셰이크가 포함되어 있다

웹 소켓은 HTTP와 어떻게 다를까?

Http는 각각의 요청에 별도의 연결을 사용한다. 이는 서버로 하여금 모든 요청에 별도의 핸드셰이크를 생성하도록 하므로 서버에게 부담이 될 수 있다. 한번 요청이 완성되면 연결은 종료된다. 반면, 웹 소켓 연결은 어느 쪽에서 중단하지 않는한 연결이 지속된다.

WebSocket 프로토콜은 독립적인 TCP 기반 프로토콜이다. HTTP와의 유일한 연관성은 핸드셰이크가 HTTP 서버에 의해 업그레이드 요청으로 해석된다는 것 뿐이다.
WebSocket은 HTTP와 별개로 동작하며, 자체적으로 TCP 기반의 프로토콜로 설계되어 있다. 즉, 서로 독립적으로 동작하며 서로 다른 프로토콜로 작동하는 것이다. 다만 업그레이드 요청이 HTTP 서버에 의해 해석된다는 것만이 TCP와 HTTP 사이의 유일한 관계이다.

또한 핸드셰이크가 유효한 HTTP 업그레이드 요청이 되도록 하여 서버가 HTTP 서버와 포트를 공유할 수 있도록 설계되었다.

WebSocket 프로토콜은 최소한의 프레이밍(minimal framing)이 있어야 한다는 원칙에 따라 설계되었다. (이는 프로토콜이 스트림 기반이 아니라 프레임 기반으로 동작하며, 유니코드 텍스트와 이진 프레임을 구분할 수 있도록 하는 것이다.)

애플리케이션 계층에 의해 WebSocket위에 계층화되는 메타데이터는, 애플리케이션에 의해 TCP 위에 계층화되는 메타데이터와 동일한 방식으로 작동할 것으로 예상된다.

일반적으로 WebSocket 프롵토콜은 웹소켓 연결에 80포트를 사용하고, TLS(Transport Layer Security, 전송 계층 보안)을 통해 터널링되는 WebSocket 연결에 포트 443을 사용한다.


Reference

profile
Good Luck!

0개의 댓글