Skip to content

NPU 디코딩 지원 원격 데스크톱 스트리밍 구현

Notifications You must be signed in to change notification settings

Real-Poo/server_client

Repository files navigation

GPU 기반 원격 데스크톱 스트리밍 클라이언트

서버에서 가상 데스크톱을 캡처하고 GPU로 인코딩한 화면 데이터를 웹소켓을 통해 수신한 후, 클라이언트에서 GPU를 활용하여 실시간으로 디코딩하는 원격 데스크톱 스트리밍 시스템입니다.

📋 목차

🎯 개요

이 프로젝트는 다음 두 가지 클라이언트 구현을 제공합니다:

  1. Python 클라이언트 (client.py): PyTorch를 사용하여 GPU에서 디코딩하고 성능 통계를 콘솔에 출력
  2. 웹 클라이언트 (client.html): ONNX Runtime을 사용하여 브라우저에서 디코딩하고 화면에 표시

서버는 화면을 캡처하고 CNN 인코더로 압축한 후, zlib으로 압축하여 웹소켓을 통해 전송합니다. 클라이언트는 수신한 데이터를 압축 해제하고 GPU로 디코딩하여 원본 화면을 복원합니다.

💻 시스템 요구사항

공통 요구사항

  • Docker: Docker Engine 20.10 이상
  • NVIDIA Container Toolkit: GPU 사용을 위한 Docker 플러그인
  • GPU: CUDA 지원 NVIDIA GPU (서버 및 Python 클라이언트에 필요)
  • 운영체제: Linux (권장), Docker가 지원되는 다른 운영체제

서버

  • Docker 이미지: Dockerfile.server 기반
  • 포트: 8765 (웹소켓)

Python 클라이언트

  • Docker 이미지: Dockerfile.client 기반
  • 네트워크: 호스트 네트워크 모드 사용

웹 클라이언트

  • 브라우저: Chrome, Edge, Firefox (최신 버전)
  • GPU: WebGL 또는 WebNN 지원 GPU
  • 서버: HTTP 서버 (정적 파일 호스팅)

🚀 사용 방법

서버 실행

  1. 서버 Docker 이미지 빌드
docker build -f Dockerfile.server -t remote-desktop-server .
  1. 서버 컨테이너 실행
docker run --gpus all -p 8765:8765 --rm \
  -v /tmp/.X11-unix:/tmp/.X11-unix \
  -e DISPLAY=:1 \
  -e QT_X11_NO_MITSHM=1 \
  -e _X11_NO_MITSHM=1 \
  -e _MITSHM=0 \
  remote-desktop-server

또는 실행 스크립트 사용:

./run_server.sh

서버는 가상 디스플레이(Xvfb)에서 화면을 캡처하고 GPU로 인코딩한 후 웹소켓 포트 8765로 전송합니다.

Python 클라이언트 실행 (Docker)

  1. 클라이언트 Docker 이미지 빌드
docker build -f Dockerfile.client -t remote-desktop-client .
  1. 클라이언트 컨테이너 실행

서버가 실행 중인 상태에서 다음 명령어로 클라이언트를 실행합니다:

docker run --gpus all --rm --network host remote-desktop-client

또는 실행 스크립트 사용:

./run_client.sh

참고:

  • --gpus all: GPU 접근 권한 부여 (필수)
  • --network host: 호스트 네트워크 모드로 서버와 통신
  • --rm: 컨테이너 종료 시 자동 삭제
  1. 성능 통계 확인

클라이언트는 콘솔에 다음과 같은 성능 통계를 실시간으로 출력합니다:

  • 프레임 번호: 수신한 프레임 수
  • FPS: 초당 프레임 수
  • 지연시간: 서버에서 클라이언트까지의 네트워크 지연 (ms)
  • 데이터 크기: 수신한 압축 데이터 크기 (bytes)
  • 디코딩 시간: GPU 디코딩에 소요된 시간 (ms)
  • 평균 디코딩 시간: 누적 평균 디코딩 시간 (ms)

예시 출력:

🔧 사용 중인 디바이스: cuda
📦 디코더 모델 로드 완료
✅ 서버에 연결됨: ws://localhost:8765
📊 프레임 #1 | FPS: 30.0 | 지연: 45.2ms | 크기: 12345 bytes | 디코딩: 8.5ms (평균: 8.5ms)
📊 프레임 #2 | FPS: 30.1 | 지연: 46.1ms | 크기: 12340 bytes | 디코딩: 8.3ms (평균: 8.4ms)
...
📈 총 100개 프레임 수신 완료 (평균 FPS: 30.2, 평균 디코딩: 8.4ms)
  1. 종료

Ctrl+C를 눌러 클라이언트 컨테이너를 종료합니다. --rm 플래그로 인해 컨테이너는 자동으로 삭제됩니다.

웹 클라이언트 실행

  1. ONNX 모델 준비

decoder.onnx 파일이 client.html과 같은 디렉토리에 있는지 확인하세요.

  1. HTTP 서버 시작
python -m http.server 8000
  1. 브라우저에서 접속
http://localhost:8000/client.html
  1. 화면 확인
  • 캔버스에 원격 데스크톱 화면이 표시됩니다
  • FPS와 지연시간이 화면 하단에 표시됩니다

📁 코드 구조

주요 파일

  • client.py: Python 클라이언트 메인 파일 (GPU 디코딩 및 성능 측정)
  • client.html: 웹 클라이언트 HTML 파일
  • decoder_model.py: 디코더 모델 정의 및 ONNX 변환 스크립트
  • server_encode.py: 서버 측 인코딩 코드
  • Dockerfile.server: 서버 Docker 이미지 빌드 파일
  • Dockerfile.client: 클라이언트 Docker 이미지 빌드 파일
  • run_server.sh: 서버 실행 스크립트
  • run_client.sh: 클라이언트 실행 스크립트

데이터 흐름

Python 클라이언트:

서버 → [인코딩] → [압축] → [웹소켓 전송] → 클라이언트 → [수신] → [압축 해제] → [GPU 디코딩] → [성능 통계 출력]

웹 클라이언트:

서버 → [인코딩] → [압축] → [웹소켓 전송] → 클라이언트 → [수신] → [압축 해제] → [GPU 디코딩] → [화면 표시]

메시지 형식

서버에서 전송하는 메시지는 다음 형식입니다:

[헤더 길이 (4 bytes)] [헤더 (JSON)] [페이로드 (zlib 압축된 latent 데이터)]

헤더 구조:

{
    "w": 80,           // latent 너비
    "h": 45,           // latent 높이
    "c": 64,           // 채널 수
    "scale": 0.1,      // 양자화 스케일
    "orig_w": 1280,    // 원본 너비
    "orig_h": 720,     // 원본 높이
    "timestamp": 1234567890.123  // 타임스탬프
}

클라이언트 동작 과정

Python 클라이언트 (client.py)

1. 디코더 모델 초기화 (GPU/CPU)
2. 웹소켓 서버에 연결
3. 반복:
   a. 메시지 수신
   b. 헤더 파싱 (길이 + JSON)
   c. zlib 압축 해제
   d. int8float32 변환 (스케일 적용)
   e. GPU에서 디코딩 (시간 측정)
   f. 성능 통계 계산 (FPS, 지연시간, 디코딩 시간)
   g. 콘솔에 통계 출력

웹 클라이언트 (client.html)

1. ONNX Runtime 초기화 (WebGL/WebNN)
2. ONNX 모델 로드
3. 웹소켓 서버에 연결
4. 반복:
   a. 메시지 수신 (ArrayBuffer)
   b. 헤더 파싱
   c. pako로 압축 해제
   d. int8  float32 변환
   e. ONNX Runtime으로 디코딩
   f. 텐서  ImageData 변환
   g. Canvas에 렌더링

⚡ 성능 최적화

GPU 사용 확인

Python 클라이언트:

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"🔧 사용 중인 디바이스: {device}")

CUDA가 사용 가능한 경우 자동으로 GPU를 사용합니다. 클라이언트 실행 시 사용 중인 디바이스가 콘솔에 출력됩니다.

웹 클라이언트:

브라우저 콘솔에서 실행 프로바이더를 확인할 수 있습니다:

  • webgl: GPU 가속 (WebGL)
  • webnn: NPU 가속 (지원되는 경우)
  • cpu: CPU만 사용

성능 향상 팁

  1. GPU 메모리 관리

    • 배치 크기를 조정하여 GPU 메모리 사용량 최적화
    • 불필요한 텐서는 즉시 해제
  2. 네트워크 최적화

    • 웹소켓 버퍼 크기 조정: max_size=1_000_000
    • 압축 레벨 조정 (서버 측)
  3. 성능 모니터링

    • client.py는 각 프레임의 디코딩 시간을 측정하여 출력
    • 100프레임마다 누적 통계 출력
    • 웹: RequestAnimationFrame 활용 (필요시)

🔧 트러블슈팅

Docker 관련

문제: GPU를 사용할 수 없음

docker: Error response from daemon: could not select device driver "" with capabilities: [[gpu]].

해결 방법:

  • NVIDIA Container Toolkit 설치 확인:
    # Ubuntu/Debian
    distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
    curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
    curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
    sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
    sudo systemctl restart docker
  • Docker가 GPU를 인식하는지 확인:
    docker run --rm --gpus all nvidia/cuda:11.8.0-base-ubuntu20.04 nvidia-smi

문제: 서버 컨테이너 실행 실패

Error: cannot connect to X server :1

해결 방법:

  • Dockerfile.server에서 Xvfb가 자동으로 시작되도록 설정되어 있습니다
  • 컨테이너 로그 확인:
    docker logs <container_id>

문제: 클라이언트가 서버에 연결할 수 없음

ConnectionRefusedError: [Errno 61] Connection refused

해결 방법:

  • 서버 컨테이너가 실행 중인지 확인:
    docker ps
  • 서버 컨테이너가 포트 8765를 리스닝하는지 확인:
    docker port <container_id>
  • 클라이언트가 --network host 옵션으로 실행되었는지 확인
  • 서버와 클라이언트가 같은 네트워크에 있는지 확인

Python 클라이언트

문제: CUDA를 사용할 수 없음

🔧 사용 중인 디바이스: cpu

해결 방법:

  • Docker 컨테이너에 --gpus all 플래그가 포함되어 있는지 확인
  • NVIDIA Container Toolkit이 설치되어 있는지 확인
  • 호스트 시스템에서 GPU가 인식되는지 확인:
    nvidia-smi

문제: 디코딩 오류

RuntimeError: Expected tensor to have size ...

해결 방법:

  • 서버와 클라이언트의 모델 버전 일치 확인
  • 헤더의 w, h, c 값이 올바른지 확인
  • 디코더 채널 수(c=64)가 서버 인코더와 일치하는지 확인

웹 클라이언트

문제: ONNX 모델을 로드할 수 없음

Error loading model: Failed to fetch

해결 방법:

  • decoder.onnx 파일이 같은 디렉토리에 있는지 확인
  • HTTP 서버가 정적 파일을 제대로 서빙하는지 확인
  • CORS 설정 확인

문제: WebGL/WebNN을 사용할 수 없음

브라우저가 GPU 가속을 지원하지 않는 경우 CPU로 폴백됩니다. 성능이 저하될 수 있습니다.

해결 방법:

  • 최신 브라우저 사용
  • GPU 드라이버 업데이트
  • 브라우저 하드웨어 가속 설정 확인

문제: 메모리 부족

대용량 화면 해상도에서 메모리 부족이 발생할 수 있습니다.

해결 방법:

  • 해상도 낮추기 (서버 설정)
  • 브라우저 메모리 제한 확인
  • 다른 탭/애플리케이션 종료

📊 성능 지표

일반적인 성능 지표:

  • 디코딩 시간: 5-20ms (GPU 사용 시)
  • FPS: 30-60 FPS (네트워크 및 GPU 성능에 따라 다름)
  • 지연시간: 50-200ms (네트워크 지연 포함)

📝 참고사항

  • 서버와 클라이언트의 모델 구조가 일치해야 합니다
  • 양자화 스케일(scale)은 서버에서 계산되어 헤더에 포함됩니다
  • 타임스탬프는 서버 시간 기준이므로, 클라이언트와 서버의 시계 동기화가 필요합니다
  • client.py는 화면 표시 없이 성능 통계만 출력합니다 (화면 표시가 필요한 경우 웹 클라이언트 사용)
  • 웹 클라이언트는 보안상의 이유로 로컬 파일 시스템에서 직접 열 수 없습니다 (HTTP 서버 필요)
  • 서버와 클라이언트는 Docker 컨테이너로 실행됩니다
  • 서버 컨테이너는 포트 8765를 호스트에 노출합니다
  • 클라이언트 컨테이너는 --network host 모드로 실행되어 서버의 localhost:8765에 연결합니다
  • 웹 클라이언트도 서버가 Docker로 실행 중이면 ws://localhost:8765로 연결할 수 있습니다
  • NVIDIA Container Toolkit이 설치되어 있어야 GPU를 사용할 수 있습니다

🔗 관련 파일

  • server_encode.py: 서버 측 인코딩 코드
  • decoder_model.py: 디코더 모델 정의
  • client.py: 클라이언트 디코딩 코드

📄 라이선스

이 프로젝트의 라이선스 정보를 여기에 추가하세요.

About

NPU 디코딩 지원 원격 데스크톱 스트리밍 구현

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published