안녕하세요, 똑똑한개발자에서 프론트엔드 개발을 맡고 있는 심재철입니다.

채팅, 주식등에서 실시간 통신에 사용되는 웹 소켓에 대해서 알아보겠습니다.

HTTP

HTTP의 특징을 나열해보겠습니다.

무상태성

HTTP만을 사용하면 서버는 클라이언트가 누구인지 기본적으로 식별하지 못합니다. 왜냐면 HTTP 자체에 어떤 상태가 있는게 아니기 때문입니다.

그렇기 때문에 세션쿠키, JWT등을 사용해서 해당 요청을 보낸 유저가 어떤 유저인지를 식별하게 됩니다.

비 연결성

서버와 클라이언트는 매번 통신할때마다 연결을 맺었다가 끊는것을 반복합니다. 어떤 클라이언트가 서버로 요청을 보냈을때 서버는 그 클라이언트와의 연결을 계속 유지하지 않습니다.

생각해보면 엄청나게 많은 요청이 서버로 들어왔는데 서버가 모든 클라이언트와 연결을 유지하고 있으면 서버 부하가 엄청 심해지겠죠?

그런 이유 때문에 이렇게 비 연결성으로 설계된게 아닌가 싶습니다.

HTTP의 단점

그렇다면 HTTP로 모든 일을 다 처리할 수 있을까요? 그렇지 않습니다.

A,B 두 유저가 서로 실시간으로 채팅을 해야한다고 해봅시다. 이걸 HTTP로 구현할 수 있을까요?? 가능은 하지만 굉장히 비효율적일것입니다.

HTTP로 실시간 통신을 구현하면 비효율적인 이유

  1. HTTP는 비 연결성이기 때문에 채팅을 보내고 받을때마다 매번 연결을 맺었다 끊었다를 반복해야하기 때문입니다. 이것은 수 많은 채팅이 요청 될 경우 서버 부하가 심해질 수 있다는 얘기입니다.

  2. A가 B에게 메세지를 보냈다고 해봅시다. A가 서버에 Hello라는 문자열을 보냈습니다. 서버에서는 이 문자열을 A가 보냈다는것을 인지할 수 있고 이것을 B에게 보내야 한다는 것을 알고 있습니다. B의 입장에서 생각해볼까요? HTTP는 기본적으로 요청을 해야 응답을 해주는 구조입니다. 그렇단 얘기는 B가 서버에 “나에게 온 메세지가 있어?”라고 계속해서 물어봐야 한다는것입니다. 이것이 Polling이라고 하는 기법입니다.

    그럼 B는 도대체 몇초에 한번씩 서버에 요청을 보내야할까요? B에게 메세지가 오지도 않았는데 혹시나 왔을 메세지 확인을 위해서 계속 서버에 요청을 보내는것이 비효율적이라는 느낌이 듭니다.

그래서 이런 경우에는 Long Polling이라는 방식을 사용합니다.

이 방식은 B가 서버에 처음 한번만 요청을 보냅니다. B와 서버는 연결을 유지하고 있다가 만약 서버에서 B에게 보내야할 채팅이 도착하면 응답을 그때 내려주고나서 연결을 종료합니다. B는 서버로부터 채팅을 받고 나서 처리한다음, 다시 서버에 연결 요청을 보냅니다. 그리고 위 과정이 계속 반복됩니다.

PollingLong Polling의 차이는 요청을 계속 보내느냐, 한번만 보내고 기다리느냐 차이입니다.

하지만 Long Polling방식을 사용하더라도 대용량 채팅의 경우 결국엔 서버로 엄청난 HTTP 요청과 응답이 오고가는것은 변함이 없습니다.

HTTP 요청이 들어왔을때 서버와 클라이언트는 매번 TCP 핸드쉐이킹을 거쳐야 하기 때문에 많은 요청에 대해 부담이 심해질 수 있습니다.

웹 소켓

이러한 HTTP를 통한 실시간 통신의 문제점 때문에 HTML5에서 드디어 웹소켓이라는것이 등장했습니다. 현재 IE 11버전 이상에서 지원되며 준수한 브라우저 지원 스펙을 가지고 있습니다.

웹 소켓의 특징

  1. 처음 한번만 HTTP 통신합니다. (연결 요청, 응답)
  2. 연결이 수립되고 나면 웹소켓이라고 하는 가벼운 메세지를 서버와 클라이언트가 주고 받는다. (HTTP에 비해 부담이 덜하다.)
  3. httphttps 와 비슷하게 wswws(보안)두가지 프로토콜이 존재합니다.

소켓 통신 연결 과정;

HTTP에서 TCP 핸드쉐이크후에 추가적으로 HTTP 핸드쉐이크를 통해 연결을 수립합니다. 그 후에는 클라이언트와 서버가 연결을 유지하면서 실시간으로 소켓을 통해 메세지를 주고 받습니다. 그리고 한쪽에서 연결을 종료시키면 서로 연결이 끊어지는 구조입니다.

클라이언트의 HTTP 연결 요청

GET /chat HTTP/1.1
Host: server.simsimjae.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://simsimjae.com

여기서 주목해야 할 부분은

  1. Upgrade: websocket: 웹소켓 연결
  2. Connection: Upgrade: 웹소켓 연결
  3. Sec-WebSocket-Key : 웹소켓 연결에 사용되는 key입니다.

웹소켓 디버깅을 하실때는 위 3가지가 잘 서버로 전송됬는지 확인하시면 됩니다.

서버의 HTTP 연결 응답

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

여기서 주목해야 할 부분은

  1. HTTP/1.1 101 Switching Protocols: 정상적인 HTTP 소켓 연결 성공 응답 코드
  2. Upgrade: websocket: 웹소켓 연결
  3. Connection: Upgrade: 웹소켓 연결
  4. Sec-WebSocket-Accept : 클라이언트 확인을 위해 사용합니다. Sec-WebSocket-Key를 SHA-1 해싱 -> base64 인코딩 후에 클라이언트로 내려준 값입니다.

입니다.

연결이 수립되고 나서는 브라우저 네이티브 WebSocket 객체를 통해 메세지를 주고 받으면 됩니다. 감사합니다.

jaecheol.sim's profile image

jaecheol.sim

2021-05-15 17:00

Read more posts by this author