본문 바로가기
C.W.K.
Stream
Lesson 06 of 07 · published

연결과 메시지 제한

~12 min · management, rate-limit, abuse

Level 0Poller
0 XP0/60 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

남용의 두 축

WebSocket 남용에는 한 출처가 너무 많은 연결 을 여는 경우와 연결 하나가 너무 많은 메시지 를 보내는 경우가 있어. 대응 방식도 달라. 연결 수 제한은 파일 디스크립터와 메모리 같은 서버 자원 고갈을 막고, 메시지 속도 제한은 연결을 끊지 않으면서 시끄럽거나 악의적인 클라이언트를 제어해.

IP 별 연결 수 제한

출발지 IP 마다 활성 연결 수를 추적하고 상한을 넘으면 코드 4029 로 거절해. HTTP 429 와 비슷하게 쓰는 애플리케이션 관례야. 프록시 뒤에서는 websocket.client.host 가 실제 클라이언트가 아닌 프록시 IP 일 수 있으니 조심해. 역방향 프록시가 X-Forwarded-For 를 올바르게 설정한다면 그 값을 써.

연결별 메시지 속도 제한

WebSocket 마다 최근 메시지 시각을 추적해. 지난 1초 동안 상한을 넘으면 그 메시지를 버리고 {type: 'error', code: 'rate_limited'} 로 응답해. 곧바로 연결을 닫으면 네트워크 장애처럼 보여 지나친 대응이 돼. 남용한 메시지만 버리고 연결은 유지해.

Code

연결 수와 메시지 속도 제한 결합하기·python
from collections import defaultdict, deque
from fastapi import WebSocket
import time

class LimitedManager:
    def __init__(self, *, max_per_ip=20, max_msg_per_sec=20):
        self.max_per_ip = max_per_ip
        self.max_msg_per_sec = max_msg_per_sec
        self.ip_counts: Dict[str, int] = defaultdict(int)
        self.msg_window: Dict[WebSocket, deque] = {}

    async def connect(self, ws: WebSocket) -> bool:
        ip = (ws.headers.get('x-forwarded-for', '').split(',')[0].strip()
              or (ws.client.host if ws.client else 'unknown'))
        if self.ip_counts[ip] >= self.max_per_ip:
            await ws.close(code=4029, reason='too many connections')
            return False
        self.ip_counts[ip] += 1
        self.msg_window[ws] = deque()
        await ws.accept()
        return True

    def check_rate(self, ws: WebSocket) -> bool:
        now = time.time()
        win = self.msg_window.get(ws)
        if win is None:
            return False
        while win and now - win[0] > 1.0:
            win.popleft()
        if len(win) >= self.max_msg_per_sec:
            return False
        win.append(now)
        return True

External links

Exercise

max_per_ip=2 로 설정하고 같은 브라우저에서 같은 엔드포인트에 탭 세 개를 열어. 세 번째 연결은 코드 4029 로 거절되어야 해. 이어서 max_msg_per_sec=5 로 설정하고 반복문에서 메시지 100개를 보내. 초당 처음 5개만 성공하고 나머지는 rate_limited 오류를 받아야 해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.