WebSocket이란?

🧐 들어가기에 앞서..

1초에 한번씩 특정 데이터를 업데이트해야되는 상황이라면, 어떤 방식으로 구현해야 될까요?
즉, 마치 실시간인 것처럼 작동하게 보이기 위해서는 어떤 통신 방법을 사용해야 될까요? 보통 아래의 두가지 방법으로 구현됩니다.

1) Polling(폴링)

2) WebSocket(웹소켓)

로봇의 데이터를 실시간처럼 받아오기 위해서 polling과 websocket 두 가지 방식을 혼용해서 사용하고 있습니다.
이 두 방식의 동작과정과 장단점을 알아보도록 하겠습니다.

1️⃣ Polling(폴링)

클라이언트가 n초 간격으로 request를 서버로 계속 날려서 response를 전달받는 방식입니다.
즉, 1초마다 업데이트되는 데이터가 존재한다면, 1초 간격으로 서버에 request를 날리는 방식입니다.

구현하기에 가장 쉬운 방법이지만, 클라이언트가 빠른 간격으로 request를 계속 날리기 때문에 클라이언트가 많아지면 서버의 부담이 늘어나게 됩니다.
그리고 HTTP Overhead가 발생합니다.

HTTP Overhead 란?

네트워크를 통해 대상으로 라우팅되는 데이터와 함께 전송되어야하는 정보를 말하며, 올바른 대상에 도달하기 위해 전송중인 데이터에 추가로 보내지는 정보를 말한다. 즉, 정보의 신뢰성 판단을 위하여 헤더 같은 정보들 때문에 오히려 데이터량이나 처리시간이 증가하는 것을 말한다.
HTTP 오버헤드

2️⃣ WebSocket(웹소켓)

웹소켓은 HTML5 표준 기술로, 사용자의 브라우저와 서버 사이의 동적인 양방향 연결 채널을 구성합니다.

Websocket API를 통해 서버로 메세지를 보내고, 별도의 request 없이 response를 받아오는 것이 가능합니다.

그리고 WebSocket 프로토콜의 특징 중 하나는 접속 확입에 HTTP를 사용하고, 그 후의 통신은 WS라는 프로토콜을 이용한다는 것입니다.

설명을 덧붙이자면, HTTP와 WebSocket은 다른 프로토콜이지만, 웹소켓은 HTTP와 함께 동작할 수 있도록 설계되어 있습니다. 웹소켓이 처음 열릴 때 HTTP 요청을 통해서 시작되고, 이후에 WebSocket tunnel로 업그레이드되기 때문에, 전통적인 80,443 포트와도 즉시 호환이 되는 겁니다.

그리고 통신시에 지정되는 URL은 http://www.sample.com/ 과 같은 형식이 아니라 ws://www.sample.com/ 과 같은 형식이 됩니다.

  • Polling vs WebSocket
  • 자세한 웹 소켓 동작 과정

Opening Handshake → Data transfer → Closing Handshake

Get Method 를 사용하고, Upgrade: websocket 헤더를 통해 웹소켓 프로토콜로 전환합니다.
HTTP에서 WS로 프로토콜 전환이 승인 되었다는 응답이 오면 Data transfer가 진행됩니다.

🛠 WebSocket in FastAPI

코드 예제

# FastAPI에서는 기본적으로 웹소켓을 지원하기 때문에 생성하는 것은 쉽다.
from fastapi import FastAPI, WebSocket 
from starlette.websockets import WebSocketDisconnect

app = FastAPI()

# websocket 데코레이터를 사용
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    # accept() 메서드는 클라이언트에게 서버가 tunnel을 여는 것을 동의 한다고 알린다. 
    따라서 처음 웹소켓 엔드포인트를 구현할 때, 필수적으로 호출되어야 한다.
    await websocket.accept()
    # 무한루프를 돌면서, 문자열 수신을 기다린다. 
    이는 HTTP 엔드포인트와 가장 다른 부분이다. tunnel이 닫힐 때까지 이 무한루프를 계속 돈다.
    try:
        while True:
            # receive_text()메서드는 클라이언트로부터 메시지를 받아올 때까지 blocking 된다.
            data = await websocket.receive_text()
            # 수신한 문자열을 클라이언트에게 전송한다.
            await websocket.send_text(f"Message text was: {data}")
    except WebSocketDisconnect:
        await websocket.close()

✓ WebSocket의 장점

  • 단순한 API로 구성되어 있습니다.
  • 양방향 메세지를 자유롭게 주고 받을 수 있습니다.
  • 채팅, 게임, 모니터링 데이터 등과 같은 실시간이 요구되는 응용프로그램의 개발을 한층 효과적으로 구현할 수 있음.
  • 웹소켓 연결의 시작은 HTTP 프로토콜을 통해 이루어지기 때문에, 기존 포트를 그대로 사용 가능.

✓ WebSocket의 단점

  • 프로그램 구현에 보다 많은 복잡성 초래합니다.
  • 서버와 클라이언트 간의 Socket 연결을 유지한다는 것 자체가 비용이 드는 일입니다. 특히나 트래픽양이 많은 서버 같은 경우에는 CPU에 큰 부담이 될 수 있습니다.
  • 서버와 클라이언트 간의 연결이 끊어졌을 때 생성되는 에러 메세지가 구체적이지 않아서 (예를 들어 여러가지 다른 이유로 연결이 끊어졌는데 에러 메세지가 같은 경우) 디버깅을 하는데 어려움이 많기도 합니다.

🔵 reference
[FastAPI/Python]양방향 통신을 위한 웹소켓 in FastAPI
[WEB]🌐 웹 소켓 (Socket) 정리 (역사부터 차근차근)
🌐 Polling / Long Polling / Server Sent Event / WebSocket 정리

0개의 댓글