치춘짱베리굿나이스

WebSocket 본문

이론적인 부분들/웹

WebSocket

치춘 2023. 7. 21. 12:51

웹소켓 (WebSocket)

Socket.io 설명이랑 묶을까 하다가 웹소켓 부분이 너무 길어져서 분리했다

설명

우리가 아는 HTTP 프로토콜은 클라이언트와 서버가 한 번 데이터를 주고받으면 대부분 연결을 끊어버리는 (비연결성) 특징을 가지고 있었다

따라서 한번 데이터를 주고받았다? 연결 유지가 끊겨버리는 것이다

하지만 채팅, 실시간 게임, 주…식과 같은 몇몇 서비스에서는 실시간으로 데이터가 이동하는 것을 보장하기 위해 서버 - 클라이언트 간 끊기지 않는 연결을 필요로 하고, 이때 사용할 수 있는 것이 WebSocket 프로토콜이다

웹소켓은 RFC6455 명세에 처음으로 정의되었으며, 서버와 브라우저 간 연결이 끊어지지 않고 유지되므로 지속적으로 데이터를 전달할 수 있다

다르게 말하면 연결 이후 별도로 연결을 해제하지 않는 이상 추가적인 HTTP 요청 없이도 데이터 전달이 양방향으로 이루어진다는 장점이 있다

웹소켓 특징

  • 서버와 클라이언트 간에 전이중 통신이 가능하다
    • 전이중 통신 (full-duplex) 이란, 서버도 데이터 송신이 가능하고 클라이언트도 데이터 송신이 가능하다는 것을 뜻한다
    • 반대로 반이중 통신 (half-duplex) 이 있으며, 이는 한 쪽이 송신하는 동안 다른 한 쪽은 수신받는 방식의 통신이다 ⇒ http가 이와 같다
  • 패킷의 크기가 상대적으로 가볍다
    • 패킷 크기의 최소치가 2바이트로, 수십 바이트를 차지하는 http 패킷에 비해 훨씬 가벼워 실시간 통신에 용이하다
  • 한번 연결하면 유지 가능하다
    • HTTP의 단점인 연결 → 연결 해제의 반복이 필요 없으며, 한번 연결하면 연결이 해제되기 전까지 연결을 유지하여 지속적으로 통신할 수 있다
  • 처음 연결을 맺을 때 HTTP 통신을 사용한다
    • 핸드쉐이킹 과정이 끝나면 웹소켓 프로토콜로 바꾸어 통신을 진행한다
    • 이때 101 Switching Protocol 코드가 응답된다
    • 이 때문에 HTTP 기반으로 작동하는 프로토콜 이라고들 한다

웹소켓 이전에 사용되던 것들

  • Polling
    • 클라이언트가 서버에게 일정 시간마다 지속적으로 요청을 보내 응답을 받는 방식
    • 폴링의 주기가 짧아질 수록 서버에 부담이 가고, 길어질 수록 실시간성이 보장되지 않는다는 문제가 있다
  • Long Polling
    • 폴링의 단점을 보완하여 나온 기법
    • 클라이언트가 요청을 보냈을 때, 서버에서는 이벤트가 아직 발생하지 않았다면 해당 연결을 끊지 않고 가지고 있다가 이벤트가 발생했을 때 응답을 보내주는 방식
    • 폴링 주기를 늘려 서버에 부담을 덜 줄 수 있다는 이점은 있지만, 이벤트가 자주 발생한다면 사실상 폴링과 다를 바가 없다
  • HTTP 스트리밍
    • 서버에 요청을 보내고 HTTP 연결을 끊지 않은 채로 지속적으로 데이터를 수신받는 기법이다
    • 폴링, 롱 폴링처럼 지속적인 요청을 보내지 않아도 되어 그 둘보다 부담이 적다
    • 연결이 끊어지지 않으므로 클라이언트가 서버에 데이터를 보내고자 할 때 무리가 있다

위의 기법들은 모두 HTTP 프로토콜 기반으로 동작하는데, HTTP는 요청 / 응답 패킷의 덩치가 생각보다 많이 크므로 (텍스트 기반인 데다가 헤더에도 데이터가 잔뜩 들어간다) 실시간 통신에는 애초에 적합하지 않다

웹소켓 데이터 프레임 구조

데이터의 단위는 프레임이며, 구조는 위 사진과 같다

  • FIN: 1비트, 뒤따라 오는 데이터가 존재하는지 여부 (본 패킷이 마지막 데이터라면 1)
  • RSV: Reserved 3비트, 현재는 쓰이지 않는다고 한다 (언젠가 미래에 쓰이겠지 하고 남겨둔 비트)
  • opcode: 4비트, 데이터 프레임을 어떻게 해석해야 할 지 알려주는 비트이다
  • MASK: 1비트, 만약 1로 설정되어 있을 경우 Masking-key가 페이로드를 마스킹하는 데에 사용되었다는 의미이다
  • Payload len: 7비트, 페이로드 데이터의 길이 (바이트 단위) 를 나타낸다
    • 이 값이 126이라면 뒤따라오는 16비트가 페이로드 길이, 0x0000 ~ 0xFFFF 가 길이가 될 수 있다
    • 이 값이 127 이상이라면 총 64비트가 페이로드 길이
  • Masking-key: 4바이트, MASK가 1일 때만 여기에 값이 들어온다
  • Payload Data: 전송하고자 하는 실질적인 데이터가 들어간다

동작 방식

정말 간략하게만 그려봤다

1. 핸드쉐이킹 요청

우선 클라이언트 측에서 핸드쉐이킹을 요청한다 (여기는 HTTP 프로토콜로 이루어진다)

헤더에 특이한 부분이 몇 개 있는데,

  • Connection: Upgrade
    • 클라이언트 측에서 현재 연결을 특정한 다른 프로토콜로 (HTTP1.1 ⇒ HTTP2, HTTP2 ⇒ WebSocket 등) 바꾸고자 할 때 사용되는 헤더이다
  • Upgrade: websocket
    • 프로토콜 중에서도 WebSocket 프로토콜로 연결을 바꾸겠다는 의미이다
    • Connection: Upgrade 와 같이 사용된다
  • Sec-Websocket-Extensions
    • 클라이언트에서 사용 가능한 웹소켓 관련 확장들을 나열한 헤더이다
    • 브라우저에서 자동 생성된다
  • Sec-Websocket-Key
    • 브라우저에서 생성한 키로, 서버가 웹소켓 프로토콜을 지원하는지 확인하는 데에 사용된다고 한다
  • Sec-Websocket-Version
    • 웹소켓 프로토콜의 버전을 명시한다

2. 핸드쉐이킹 응답

웹소켓 사용이 가능하다면 서버 측에서는 응답을 보낸다

  • 응답 코드 101 Switching Protocols
    • 지금부터 통신에 사용할 프로토콜이 변경된다
  • Sec-Websocket-Accept
    • 클라이언트에서 보낸 Sec-Websocket-Key와 한 쌍을 이루며, 서버에서 웹소켓이 사용가능함을 알리는 수단이 된다

이 응답에는 Sec-Websocket-Extensions 가 명시되어 있지 않은데, 그렇다는 것은 클라이언트에서 보낸 확장 중 서버에서 지원하는 확장이 없다는 뜻이다

날림으로 간단하게 작성한 서버라 어쩔 수 없다

3. 통신 시작 (데이터 교환)

여기부턴 HTTP를 사용하지 않고 본격적으로 웹소켓 프로토콜을 사용하여 프레임을 주고받는다

이미지에서 프레임 맨 앞에 숫자가 계속 붙어있는데, 이것은 내가 socket.io를 사용해서 자동으로 붙은 숫자이다

빨간 화살표는 서버에서 클라이언트로 날아오는 데이터, 파란 화살표는 클라이언트에서 서버로 날아오는 데이터로, 브라우저에서 확인할 수 있다

가만히 놔두면 실컷 핑퐁만 하기도 한다

2번이 PING, 3번이 PONG이다 (…)

주고받는 프레임은 대표적으로 아래와 같다

  • 텍스트 프레임: 평범한 텍스트 데이터가 담겨 있다
  • 이진 데이터 프레임: 이진 (Binary) 데이터가 담겨 있다
  • 핑퐁 프레임: 위의 이미지에서 2, 3의 향연이 바로 그것이다… 커넥션이 유지되고 있는지 확인을 위해 보내는 프레임으로, 브라우저나 서버에서 자동으로 생성한다

보통 메시지는 텍스트로 처리하고, 이미지 등의 미디어를 이진 데이터 프레임으로 보내는 경우가 많아보인다

4. 통신 종료

둘 중 어느 한 쪽이라도 통신 종료를 수행하면 연결이 끊어진다

위에서 41번 메시지가 통신 종료를 요청하는 메시지이다

여기서는 클라이언트에서 통신을 끊어버렸다


참고자료

https://socket.io/docs/v4/

https://www.polarsparc.com/xhtml/WebSockets-02.html

https://www.joinc.co.kr/w/man/12/websocket

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Upgrade

https://developer.mozilla.org/en-US/docs/Web/HTTP/Protocol_upgrade_mechanism

https://ko.javascript.info/websocket

https://hudi.blog/websocket-with-nodejs/

'이론적인 부분들 > ' 카테고리의 다른 글

OAuth  (0) 2023.07.25
CORS  (0) 2023.06.17
DOM과 웹 렌더링  (0) 2023.05.19
JWT  (0) 2022.10.10
로그인, 인증, 인가  (0) 2022.10.08
Comments