[React의 모든것] WebSocket (채팅)

이준명·2022년 1월 9일
13

React의 모든것

목록 보기
3/3
post-thumbnail
post-custom-banner

🤔 웹소켓이란?

웹소켓(WebSocket)은 TCP 연결에 완전한 이중 통신 채널을 제공하는 컴퓨터 프로토콜이다. (HTTP와 다름 - 둘다 OSI 7계층에 위치해 있고 4계층의 TCP에 의존함. 웹소켓은 HTTP 프로토콜과 호환이 된다.)

주의 - 서버와 클라이언트간의 웹소켓 연결은 HTTP 프로토콜을 통해 이루어지는데 연결이 정상적으로 이루어진다면 서버와 클라이언트 간에 웹소켓 연결(TCP/IP기반)이 이루어지고 일정 시간이 지나면 HTTP 연결은 자동으로 끊어짐.

서버와 클라이언트 간의 효율적인 양방향 통신과 데이터 전송을 실현하기 위한 구조이다.

우리는 기본적으로 클라이언트와 서버의 관계를 stateless 하게 이루어져 있다고 알고있습니다. 클라이언트에서 Request를 날리면 서버에서 Response를 보내는 과정. (즉 HTTP통신은 클라이언트가 요청을 보내는 경우에만 서버가 응답하는 단방향 통신)

웹소켓은 statefull 하다. 매번 요청을 보내는 것이 아니라 한번의 요청으로 handShake 과정을 통해 연결을 유지해서 양방향 통신과 데이터 이동이 가능하게되는 것이다. (일반적으로 웹어플리케이션에서는 데이터의 빠른 실시간 업데이트가 아주 중요한 요소이기 때문에 웹 소켓의 중요도가 높아지고 있다.)

😏 웹소켓의 특징

양방향 통신(Full-Duplex)

  • 데이터 송수신을 동시에 처리할수 있다.
  • 클라이언트와 서버가 서로 원할때 데이터를 주고 받는다.

실시간 네트워킹(Real Time-Networking)

  • 웹 환경에서 연속된 데이터를 빠르게 노출한다.
  • 여러 단말기에서 데이터를 빠르게 교환
    ex) 채팅, 주식, 비디오 데이터

추가

  • header가 상당히 작아 overhead가 적은 특징이 있다.
  • 웹소켓 프로토콜은 HTTP Polling 과 같은 반이중 방식에 비해 더 낮은 부하를 사용한다.

Polling : 일정 주기로 요청을 송신하는 것.

  • 실시간 네트워킹에서는 언제 통신이 발생할지 예측이 불가능하므로 불필요한 요청과 연결을 생성한다.

  • 즉 바뀐게 없는데도 요청을 계속하고 응답도 계속 한다.

Long Polling

  • Polling의 단점을 해소하기 위해서 서버에서 조금 더 대기를 하면서, 이벤트가 발생할 때 응답을 하는 방식이다.

  • 응답을 받으면 끊고 다시 재요청한다.
    결국 많은 양의 메시지가 쏟아지면 Polling과 동일해진다.

Streaming

  • 서버에 요청 보내고 끊기지 않은 연결상태에서 끊임없이 데이터를 수신한다.

  • 클라이언트에서 서버로의 데이터 송신이 어렵다.

  • 세 개의 방식 모두 HTTP를 통해 통신하기 때문에 요청/응답 모두 헤더가 불필요하게 크다는 단점이 있다.

😎 웹소켓 종류

socket.io

인터넷 익스플로러 구버전의 사용자는 웹소켓으로 작성된 웹페이지를 볼 수 없다. 이를 해결하기위해 socket.io는 웹페이지가 열리는 브라우저가 웹소켓을 지원하면 일반 웹소켓 방식으로 동작하고 지원하지 않는 브라우저라면 http를 이용해 웹소켓을 흉내내는 방식으로 통신을 지원한다. socket.io는 node.js에 종속적이다.

sockjs

spring에서 위와 같은 브라우저 문제를 해결하기 위한 방법으로 sockjs를 해결책으로 제공한다. 서버 개발시 일반 웹소켓으로 통신할지 sockjs 호환으로 통신할지 결정할 수 있다. 클라이언트는 sockjs를 통해 서버랑 통신한다.

stomp

stomp는 단순 텍스트 지향 메시징 프로토콜이다. spring에 종속적이고, 구독방식으로 사용하고 있다. (가벼워서 많이 사용한다.)
stomp는 웹소켓 위에서 동작하는 프로토콜로써, 클라이언트와 서버가 전송할 메시지 유형, 형식, 내용들을 정의하는 매커니즘이다.

node를 이용할땐 socket.io를 주로 사용하고, spring을 사용할땐 stomp, sockjs를 주로 사용한다.

😤 웹소켓 리액트 적용

리액트 코드 (나의 프로젝트 코드...미흡하다..)

import SockJs from "sockjs-client";
import StompJs from "stompjs";
//stomp와 sockjs 패키지로 깔고 임포트!!

const sock = new SockJs("http://서버주소");
//client 객체 생성 및 서버주소 입력

const stomp = StompJs.over(sock);
//stomp로 감싸기

const stompConnect = () => {
    try {
      stomp.debug = null;
      //웹소켓 연결시 stomp에서 자동으로 connect이 되었다는것을 
      //console에 보여주는데 그것을 감추기 위한 debug
      
      stomp.connect(token, () => {
        stomp.subscribe(
          `서버주소`,
          (data) => {
            const newMessage = JSON.parse(data.body);
            //데이터 파싱
          },
          token
        );
      });
    } catch (err) {
      
    }
  };

//웹소켓 connect-subscribe 부분

const stompDisConnect = () => {
    try {
      stomp.debug = null;
      stomp.disconnect(() => {
        stomp.unsubscribe("sub-0");
      }, token);
    } catch (err) {
      
    }
  };
//웹소켓 disconnect-unsubscribe 부분
// 웹소켓을 disconnect을 따로 해주지 않으면 계속 연결되어 있어서 사용하지 않을때는 꼭 연결을 끊어주어야한다. 

const SendMessage = () => {
    stomp.debug = null;
    const data = {
      type: "TALK",
      roomId: roomId,
      sender: sender_nick,
      message: message,
      createdAt: now,
    };
  //예시 - 데이터 보낼때 json형식을 맞추어 보낸다.
    stomp.send("/pub/chat/message", token, JSON.stringify(data));
  };
//웹소켓 데이터 전송 부분

전체적인 stomp의 흐름

  1. 서버와 연결할 클라이언트 객체 생성

  2. 서버와 연결할 클라이언트 connection

  3. 메세지 전송 전 subscriber와 sender를 지정

  4. subscribe를 하면 해당 url로 나에게 메세지를 보낼 수 있는 경로가 생김.

  5. sender를 하면 send 하는 데이터를 해당 url로 전송.

이해를 돕기 위한 그림...(직접 그렸지만 창피하다..)

내가 만든 웹페이지의 채팅기능 모습

profile
조금씩 나아가기
post-custom-banner

0개의 댓글