221103 TIL [Spring boot + React]실시간 채팅 기능 구현하기 - 1

축구 커뮤니티 사이트의 기능 중 하나인 실제 경기가 진행되는 시간에  채팅방이 열려  실시간으로 응원할 수 있는 기능을 구현하기 위해 실시간 채팅 기능을 구현하고자 한다.  아래 화면은 whimsical 디자인 툴을 이용해서 디자인한 화면인데 이 화면에서 가장 핵심은 실시간 응원인 실시간 채팅 기능이다. 그래서 오늘 짧게나마 실시간 채팅 구현 방법을 공부해 봤다.

구현해야하는 화면

 

우선 실시간으로 채팅을 구현하는 방법으로는 HTTP와  WebSoket 방법이 존재한다.

HTTP의 특징

http통신의 특징부터 알아보자

  •  http 통신은 단방향(비연결성)이다.
    •  클라이언트가 보낸 요청에 대해 서버가 응답을 마치면 맺었던 연결을 끊어 버리는 비연결성 성질
  •  request - response 구조이다. 
    • 서로 지속적으로 연결되어 있는 형태가 아닌 단방향 통신이기 때문에  통신이 이루어질 때마다 많은 양의 데이터가 오고 간다.

http 통신으로 실시간 채팅을 구현하려면 기존 방법으로는 한계가 존재한다.

 

실시간 채팅의 동작 과정으로는

  1. 사용자 1이 서버에 메시지를 전송하고,
  2. 서버는 사용자 1로부터 받은 메시지를 사용자 2에게 전송하고,
  3. 사용자 2는 자신에게 온 메시지를 확인한다.

이렇게 동작하는데 http 통신의 문제는 사용자가 요청을 해야 서버가 응답을 하는 request - response 구조이기 때문에 서버가 사용자 2에게 사용자 1에게로부터 메시지가 왔다는 것을 알려주려고 해도 사용자 2가 요청을 보내지 않으면 서버는 혼자 응답을 해줄 수가 없다.

사용자 2도 자신에게 메시지가 왔는지 안 왔는지 알 수가 없기 때문에 언제 서버에게 메시지를 달라고 요청할 수가 없다.

https://kamang-it.tistory.com/entry/Webhttp%ED%86%B5%EC%8B%A0%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%96%91%EB%B0%A9%ED%96%A5-%ED%86%B5%EC%8B%A0%EA%B8%B0%EB%B2%95-long-polling

 

이런 문제가 있음에도 채팅을 구현할 수 있는 방법이 있다.  비동기 통신을 통해 일정 시간마다 server한테 자신에게 보낼 정보가 있는지 요청을 하는 것이다.

하지만 이 방법은 메시지가 없음에도 불구하고 주기적으로 서버에게 요청을 하기 때문에 서버에 무리가 가며, 실시간 채팅을 구현하기 위해서는 서버에 요청하는 주기를 짧게 하면 서버에 큰 부하가 간다. 

위와 같은 방법을 polling 방법이라고 한다.

Polling

https://iborymagic.tistory.com/92

polling 방식은 위에서 설명했던 것처럼 클라이언트와 서버가 실시간 통신을 하는 것처럼 느끼기 위해 클라이언트가 서버에 일정한 주기로 요청을 보내는 방식을 말한다.

하지만 일정한 시간마다 요청을 보내는 것일 뿐이지 실제로는 실시간을 보장할 수는 없다. 만일 실시간성을 구현하기 위해 요청을 보내는 간격을 줄일 수 있지만 줄이게 되면 서버에 큰 무리가 간다는 문제가 있다.

 

Long Polling

https://iborymagic.tistory.com/92

Long Polling 방식도 Polling 방식과 마찬가지로 서버에 지속적으로 요청을 보내는 점에서 동일하지만 long polling방식은 클라이언트가 서버에 요청을 보내고 기다리고 있으면 서버에서 클라이언트로 전달할 이벤트가 발생하는 순간 서버가 응답 메시지를 전달하면서 연결이 종료된다. 그리고 바로 클라이언트는 서버에게 또 요청을 보내고 이벤트가 발생해 응답이 있을 때까지 기다린다. 

클라이언트는 무한히 응답을 기다리지 않고 서버에서 time-out이 되면 접속이 끊겼다가 다시 요청을 보낸다.

 

WebSocket

웹소켓은  Web Browser와 Server 간에 메시지 교환을 위한 양방향 통신 규격이다.

 

https://sahansera.dev/understanding-websockets-with-aspnetcore-5/

 

웹소켓의 특징

  • 양방향 통신
    • 클라이언트가 요청을 보내야만 서버가 응답을 하는 단방향 통신과 달리 클라이언트와 서버가 서로 원할 때 데이터를 주고받을 수 있다.
  • Handshake 
    • WebSocket으로 통신을 하려면 최초 접속 시에 HTTP의 Upgrade 헤더 필드를 사용해서 프로토콜을 WebSocket이라는 프로토콜로 변경하는 핸드쉐이크를 실시한다.

 

WebSocket Handshake

WebSocket으로 통신하기 위해 클라이언트가 handshake 요청을 보낸다. (HTTP upgrade 헤더를 사용해 HTTP 내의 웹 소켓 프로토콜로 변경) Upgrade: websocket 헤더와 함께 랜덤 하게 생성한 키를 서버에 보내면 해당 요청에 따라 프로토콜을 바꾼다는 상태 코드인 [101 Switching Protocols]으로 반환한다.

 

맨 처음에 클라이언트가 handshake 요청을 보낸다.

이때 요청에는 Upgrade: websocket 헤더와 랜덤 하게 생성된 키가 담긴 채로 전송된다.

그러면 서버는 해당 요청에 따라 프로토콜을 바꾼다는 상태 코드인 101 Switching Protocols로 응답을 한다.

웹소켓을 이용해 통신을 하게 된다.

 

HTTP 1.1로 요청을 하고, 요청 헤더에는 핸드쉐이크에 필요한 키와 소켓 버전 등을 포함하고 있다.

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

 

WebSocket vs HTTP

Http의 특징

  • Client가 요청을 보내는 경우에만 Server가 응답하는 단방향 통신
  • Server로부터 응답을 받은 후에는 연결이 바로 종료
  • 실시간 연결이 아니고, 필요한 경우에만 Server로 요청을 보내는 상황에 유리
  • 요청을 보내 Server의 응답을 기다리는 애플리케이션의 개발에 주로 사용

WebSocket의 특징

  • Client와 Server가 계속 연결을 유지하는 양방향 통신
  • Client와 Server가 실시간으로 데이터를 주고받는 상황이 필요한 경우에 사용 ex) 채팅, 주식