본문 바로가기
웹/웹 지식

[웹 지식] WebSocket 개념과 실제 프로젝트 명세서 예시

by 클레어몬트 2025. 6. 11.

채팅 시스템은 거의 WebSocket으로 구현한다. 오늘은 Unix프로그래밍 수업에서 배웠던 소켓과 같은 부류인 웹소켓에 대하 알아보자!

ㅁWebSocket: 하나의 TCP 연결을 통해 클라이언트와 서버 간에 실시간, 양방향 통신을 가능하게 해주는 프로토콜

웹소켓 이미지를 오늘 처음 알았다..

 

2011년 IETF에 의해 RFC 6455로 표준화되었으며, HTML5의 일부로 웹 브라우저에서 기본적으로 지원된다

 

 

1. WebSocket 특징

  • Full-duplex 통신
    HTTP는 요청-응답 기반의 Half-duplex 구조이나, WebSocket은 요청 없이도 서버가 클라이언트에게 자유롭게 데이터를 보낼 수 있는 구조이다. 이를 통해 실시간 알림, 채팅, 게임 등에서 즉각적인 반응을 구현할 수 있다.
  • 연결 유지(Persistent Connection)
    WebSocket은 최초 연결 시 HTTP 프로토콜을 사용해 핸드셰이크를 진행한 후, TCP 기반의 연결을 유지한다. 따라서 매번 새로 연결을 생성하지 않아도 되어 오버헤드가 줄어든다.
  • 헤더 오버헤드 감소
    HTTP 요청과 응답은 많은 양의 헤더 정보를 포함하고 있지만, WebSocket은 최초 핸드셰이크 이후에는 최소한의 헤더만을 사용하여 네트워크 사용량이 적다.

 

 

2. WebSocket 작동 방식

  1. 클라이언트가 HTTP를 통해 서버에 WebSocket 연결을 요청한다.
  2. 서버가 101 Switching Protocols 응답을 보내며 프로토콜을 WebSocket으로 전환한다.
  3. 연결이 성립되면, 양방향 통신이 가능해진다.
  4. 연결 종료 시 클라이언트 또는 서버가 close 프레임을 전송하여 연결을 닫는다.
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Version: 13

 

 

 

아래는 실제 내가 프로젝트를 진행하며 작성했던 WebSocket 명세서이다

[WebSocket 명세서 예시] - SK AXIS: AI 면접관 도우미

항목 내용
URL ws://sk-axis-fastapi:8000/ws/nonverbal
Protocol WebSocket
연결 시점 면접 시작 시 Vue에서 연결
종료 시점 면접 종료 시 Vue에서 .close() 호출

 

전송 데이터 형식 (1초 주기)

[
  {
    "interviewee_id": 101,
    "is_speaking": false,
    "posture": {
      "leg_spread": 0,
      "leg_shake": 0,
      "head_down": 0
    },
    "facial_expression": {
      "smile": 0,
      "neutral": 4,
      "embarrassed": 0,
      "tearful": 0,
      "frown": 0
    }
  },
  {
    "interviewee_id": 102,
    "is_speaking": true,
    "posture": {
      "leg_spread": 1,
      "leg_shake": 0,
      "head_down": 2
    },
    "facial_expression": {
      "smile": 1,
      "neutral": 3,
      "embarrassed": 0,
      "tearful": 0,
      "frown": 0
    }
  }
]

 

 

코드 구현 예시

① websocket.py (FastAPI 라우터)

from fastapi import APIRouter, WebSocket, WebSocketDisconnect
import json

router = APIRouter()

@router.websocket("/ws/nonverbal")
async def nonverbal_ws_endpoint(websocket: WebSocket):
    await websocket.accept()
    print("🟢 WebSocket 연결됨")

    try:
        while True:
            data = await websocket.receive_text()
            nonverbal_payload = json.loads(data)

            # 로그 출력 또는 저장 로직 삽입
            print(f"수신 데이터: {nonverbal_payload}")

            # 필요시 응답을 클라이언트로 보낼 수 있음 (현재는 단방향)
            # await websocket.send_text("수신 완료")
    except WebSocketDisconnect:
        print("🔴 WebSocket 연결 종료")

 

 

② main.py

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from websocket import router as websocket_router

app = FastAPI()

# CORS 설정 (Vue와 통신 위해 필요)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 프로덕션에선 정확한 origin 설정 권장
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# WebSocket 라우터 등록
app.include_router(websocket_router)

 

 

③ WebSocketClient.vue (Vue 컴포넌트)

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'

let socket = null

const sendData = () => {
  const data = [
    {
      interviewee_id: 101,
      is_speaking: false,
      posture: { leg_spread: 0, leg_shake: 0, head_down: 0 },
      facial_expression: { smile: 0, neutral: 4, embarrassed: 0, tearful: 0, frown: 0 }
    },
    {
      interviewee_id: 102,
      is_speaking: true,
      posture: { leg_spread: 1, leg_shake: 0, head_down: 2 },
      facial_expression: { smile: 1, neutral: 3, embarrassed: 0, tearful: 0, frown: 0 }
    }
  ]

  if (socket && socket.readyState === WebSocket.OPEN) {
    socket.send(JSON.stringify(data))
  }
}

onMounted(() => {
  socket = new WebSocket('ws://sk-axis-fastapi:8000/ws/nonverbal')

  socket.onopen = () => {
    console.log('🟢 WebSocket 연결 성공')
    setInterval(sendData, 1000) // 1초 주기 전송
  }

  socket.onclose = () => {
    console.log('🔴 WebSocket 연결 종료')
  }

  socket.onerror = (err) => {
    console.error('⚠️ WebSocket 에러 발생', err)
  }
})

onBeforeUnmount(() => {
  if (socket) {
    socket.close()
  }
})
</script>

 

 

 

3. WebSocket vs HTTP vs SSE 정리표

 

 

 

4. WebSocket 활용 분야

  • 실시간 채팅 서비스 (예: Slack, Discord)
  • 실시간 주식/코인 시세 스트리밍
  • 온라인 게임 서버
  • 실시간 알림 시스템 (Push Notification)
  • 화상 회의 및 음성 통화 서비스

 

 

 

+ 보안과 WebSocket

WebSocket도 보안 연결을 위해 HTTPS의 대응인 WSS(WebSocket Secure) 프로토콜을 지원한다. wss://는 TLS 암호화가 적용된 WebSocket 연결을 의미하며, 중간자 공격(MITM)을 방지할 수 있다!