서버에서 가상 데스크톱을 캡처하고 GPU로 인코딩한 화면 데이터를 웹소켓을 통해 수신한 후, 클라이언트에서 GPU를 활용하여 실시간으로 디코딩하는 원격 데스크톱 스트리밍 시스템입니다.
이 프로젝트는 다음 두 가지 클라이언트 구현을 제공합니다:
- Python 클라이언트 (
client.py): PyTorch를 사용하여 GPU에서 디코딩하고 성능 통계를 콘솔에 출력 - 웹 클라이언트 (
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 (웹소켓)
- Docker 이미지:
Dockerfile.client기반 - 네트워크: 호스트 네트워크 모드 사용
- 브라우저: Chrome, Edge, Firefox (최신 버전)
- GPU: WebGL 또는 WebNN 지원 GPU
- 서버: HTTP 서버 (정적 파일 호스팅)
- 서버 Docker 이미지 빌드
docker build -f Dockerfile.server -t remote-desktop-server .- 서버 컨테이너 실행
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로 전송합니다.
- 클라이언트 Docker 이미지 빌드
docker build -f Dockerfile.client -t remote-desktop-client .- 클라이언트 컨테이너 실행
서버가 실행 중인 상태에서 다음 명령어로 클라이언트를 실행합니다:
docker run --gpus all --rm --network host remote-desktop-client또는 실행 스크립트 사용:
./run_client.sh참고:
--gpus all: GPU 접근 권한 부여 (필수)--network host: 호스트 네트워크 모드로 서버와 통신--rm: 컨테이너 종료 시 자동 삭제
- 성능 통계 확인
클라이언트는 콘솔에 다음과 같은 성능 통계를 실시간으로 출력합니다:
- 프레임 번호: 수신한 프레임 수
- 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)
- 종료
Ctrl+C를 눌러 클라이언트 컨테이너를 종료합니다. --rm 플래그로 인해 컨테이너는 자동으로 삭제됩니다.
- ONNX 모델 준비
decoder.onnx 파일이 client.html과 같은 디렉토리에 있는지 확인하세요.
- HTTP 서버 시작
python -m http.server 8000- 브라우저에서 접속
http://localhost:8000/client.html
- 화면 확인
- 캔버스에 원격 데스크톱 화면이 표시됩니다
- 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 // 타임스탬프
}1. 디코더 모델 초기화 (GPU/CPU)
2. 웹소켓 서버에 연결
3. 반복:
a. 메시지 수신
b. 헤더 파싱 (길이 + JSON)
c. zlib 압축 해제
d. int8 → float32 변환 (스케일 적용)
e. GPU에서 디코딩 (시간 측정)
f. 성능 통계 계산 (FPS, 지연시간, 디코딩 시간)
g. 콘솔에 통계 출력1. ONNX Runtime 초기화 (WebGL/WebNN)
2. ONNX 모델 로드
3. 웹소켓 서버에 연결
4. 반복:
a. 메시지 수신 (ArrayBuffer)
b. 헤더 파싱
c. pako로 압축 해제
d. int8 → float32 변환
e. ONNX Runtime으로 디코딩
f. 텐서 → ImageData 변환
g. Canvas에 렌더링Python 클라이언트:
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"🔧 사용 중인 디바이스: {device}")CUDA가 사용 가능한 경우 자동으로 GPU를 사용합니다. 클라이언트 실행 시 사용 중인 디바이스가 콘솔에 출력됩니다.
웹 클라이언트:
브라우저 콘솔에서 실행 프로바이더를 확인할 수 있습니다:
webgl: GPU 가속 (WebGL)webnn: NPU 가속 (지원되는 경우)cpu: CPU만 사용
-
GPU 메모리 관리
- 배치 크기를 조정하여 GPU 메모리 사용량 최적화
- 불필요한 텐서는 즉시 해제
-
네트워크 최적화
- 웹소켓 버퍼 크기 조정:
max_size=1_000_000 - 압축 레벨 조정 (서버 측)
- 웹소켓 버퍼 크기 조정:
-
성능 모니터링
client.py는 각 프레임의 디코딩 시간을 측정하여 출력- 100프레임마다 누적 통계 출력
- 웹: RequestAnimationFrame 활용 (필요시)
문제: 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옵션으로 실행되었는지 확인 - 서버와 클라이언트가 같은 네트워크에 있는지 확인
문제: 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: 클라이언트 디코딩 코드
이 프로젝트의 라이선스 정보를 여기에 추가하세요.