# ClientTester - MMO 서버 테스트 도구 MMO Game Server의 네트워크 성능 검증 및 부하 테스트를 위한 클라이언트 시뮬레이터. --- ## 1. 환경 (라이브러리) | 항목 | 버전 | 용도 | |------|------|------| | .NET | 9.0 | 런타임 | | LiteNetLib | 2.0.2 | UDP 네트워크 통신 (서버와 동일) | | protobuf-net | 3.2.56 | 패킷 직렬화/역직렬화 | | Serilog | 4.3.1 | 구조적 로깅 | | Serilog.Sinks.Console | 6.0.0 | 콘솔 출력 | | Serilog.Sinks.File | 7.0.0 | 파일 로깅 | | Microsoft.Diagnostics.NETCore.Client | 0.2.553101 | 크래시 힙 덤프 (Release만) | ### 빌드 ```bash cd ClientTester/EchoClientTester dotnet build ``` --- ## 2. 디렉토리 구조 ``` ClientTester/ ├── EchoClientTester/ │ ├── Program.cs # 진입점 (대화형 + CLI) │ ├── EchoClientTester.csproj │ ├── Vector3.cs # 위치 구조체 │ │ │ ├── DummyService/ # 이동 테스트 │ │ ├── DummyClientService.cs # 다중 더미 클라 관리 │ │ ├── DummyClients.cs # 개별 더미 클라 (이동 시뮬) │ │ └── MapBounds.cs # 맵 경계 / 벽 충돌 │ │ │ ├── EchoDummyService/ # Echo RTT 테스트 │ │ ├── EchoDummyClientService.cs # 다중 에코 클라 관리 │ │ └── EchoDummyClients.cs # 개별 에코 클라 (RTT 측정) │ │ │ ├── StressTest/ # 부하/스트레스 테스트 │ │ ├── StressTestService.cs # 오케스트레이터 (Ramp-up, 통계, CSV) │ │ └── StressTestClient.cs # 통합 클라 (이동 + Echo 동시) │ │ │ ├── Packet/ # 패킷 정의 (서버와 동일 프로토콜) │ │ ├── PacketHeader.cs # PacketCode Enum │ │ ├── PacketBody.cs # Protobuf 패킷 클래스 │ │ └── PacketSerializer.cs # 직렬화 유틸 │ │ │ └── Utils/ │ └── CrashDumpHandler.cs # 크래시 로그 + 힙 덤프 │ └── TempServer/ # 간이 에코 서버 (독립 테스트용) └── Program.cs ``` --- ## 3. 사용방법 ### 3.1 대화형 모드 ```bash dotnet run ``` ``` ========== 더미 클라 테스터 ========== 1. 에코 서버 2. 더미 클라(이동만) 3. 스트레스 테스트 (부하) ==================================== 1 / 2 / 3 : ``` | 모드 | 설명 | |------|------| | 1. 에코 서버 | Echo 패킷 송수신, RTT(Round-Trip Time) 측정 | | 2. 더미 클라 | 이동(Transform) 패킷 전송, 패킷 손실률 측정 | | 3. 스트레스 테스트 | Ramp-up + 이동 + Echo 동시, 퍼센타일 레이턴시, CSV 내보내기 | ### 3.2 CLI 모드 (스트레스 테스트) ```bash # 기본 실행 (50명, 60초) dotnet run -- stress # 100명 클라이언트, 120초 테스트 dotnet run -- stress -c 100 -d 120 # 원격 서버 대상, 커스텀 설정 dotnet run -- stress -c 200 -d 60 -r 500 -b 20 --ip 192.168.0.10 --port 9500 # 도움말 dotnet run -- --help ``` #### CLI 옵션 | 옵션 | 축약 | 기본값 | 설명 | |------|------|--------|------| | `--clients` | `-c` | 50 | 총 클라이언트 수 | | `--duration` | `-d` | 60 | 테스트 지속 시간 (초, 0=무제한) | | `--interval` | `-i` | 100 | 패킷 전송 주기 (ms) | | `--ramp` | `-r` | 1000 | Ramp-up 간격 (ms) | | `--batch` | `-b` | 10 | Ramp-up 당 추가 클라이언트 수 | | `--ip` | | localhost | 서버 IP 주소 | | `--port` | | 9500 | 서버 포트 | ### 3.3 출력 파일 | 경로 | 내용 | |------|------| | `logs2/log_{timestamp}.txt` | 전체 실행 로그 | | `results/stress_{N}clients_{timestamp}.csv` | 스트레스 테스트 결과 (클라이언트별 통계) | | `crashes/crash_{timestamp}.log` | 크래시 스택 트레이스 | | `crashes/crash_{timestamp}.dmp` | 힙 덤프 (Release 빌드만) | --- ## 4. 파이프라인 ### 4.1 에코 테스트 (모드 1) ``` [클라이언트 N개 동시 생성] ↓ [연결] UDP Connect → ServerBase.OnConnectionRequest() ↓ [PollLoop] 10ms 주기로 네트워크 이벤트 처리 [SendLoop] 100ms 주기로 Echo 패킷 전송 ↓ [송신] EchoPacket { Str = "Echo seq:{N}" } → PacketSerializer.Serialize() → 4바이트 헤더(type + size) + Protobuf 페이로드 → DeliveryMethod.ReliableUnordered ↓ [수신] 서버가 Echo 패킷 그대로 반환 → seq 번호로 pendingPings 조회 → RTT 계산: (수신시각 - 송신시각) / Stopwatch.Frequency ↓ [통계] 클라이언트별: AvgRTT, LastRTT, Sent, Recv, PacketLoss% 전체: 총 Sent/Recv, 평균 RTT ``` ### 4.2 이동 테스트 (모드 2) ``` [클라이언트 N개 동시 생성] ↓ [연결 + 인증] DummyAccTokenPacket { Token = clientId } → DeliveryMethod.ReliableOrdered ↓ [이동 시뮬레이션 - UpdateDummy()] ┌────────────────────────────────────────┐ │ 1. 델타 타임 계산 (Stopwatch) │ │ 2. 남은 거리 = 0 이면: │ │ - 벽 근처? → 반대 방향 회전 │ │ - 아니면 → 현재 방향 ±30도 랜덤 회전 │ │ - 목표 거리 = moveSpeed × (3~12초) │ │ 3. 이번 틱 이동 (moveSpeed × delta) │ │ 4. MapBounds.Clamp() → 벽 충돌 처리 │ └────────────────────────────────────────┘ ↓ [송신] TransformPlayerPacket { PlayerId, Position(X,0,Z), RotY } → DeliveryMethod.Unreliable (손실 감수) ↓ [통계] 클라이언트별: Sent, Recv, PacketLoss% ``` ### 4.3 스트레스 테스트 (모드 3 / CLI) ``` [설정 입력] CLI 인자 또는 대화형 입력 ↓ [Ramp-up Loop] ┌────────────────────────────────────┐ │ rampInterval(1000ms)마다 │ │ clientsPerRamp(10)명씩 클라이언트 생성 │ │ → totalClients 도달 시 중단 │ └────────────────────────────────────┘ ↓ (병렬 실행) [PollLoop] 10ms 주기 네트워크 이벤트 [SendLoop] sendInterval(100ms) 주기 ├─ UpdateAndSendTransform() (이동 - Unreliable) └─ SendPing() (Echo - ReliableUnordered) [StatsLoop] 10초마다 실시간 통계 출력 ↓ [지속시간 만료 또는 Ctrl+C] ↓ [최종 리포트] ├─ 처리량: 총 Sent/Recv, 패킷/초 ├─ 레이턴시: Min, Avg, P50, P95, P99, Max ├─ 최악 RTT 상위 5 클라이언트 상세 └─ CSV 파일 자동 저장 ``` ### 4.4 패킷 직렬화 파이프라인 ``` 객체 (e.g. TransformPlayerPacket) ↓ protobuf-net Serialize → byte[] payload ↓ PacketSerializer.Serialize() ↓ ┌──────────────────────────────┐ │ [2B type] [2B size] [payload] │ │ ushort ushort byte[] │ └──────────────────────────────┘ ↓ NetDataWriter.Put(data) ↓ peer.Send(writer, DeliveryMethod) ``` --- ## 5. 테스트 모드별 기능 비교 | 기능 | 에코 (1) | 이동 (2) | 스트레스 (3) | |------|:--------:|:--------:|:------------:| | 동시접속 클라이언트 | 10 (고정) | 10 (고정) | N (설정 가능) | | 인증 패킷 전송 | X | O | O | | 이동 시뮬레이션 | X | O | O | | Echo RTT 측정 | O | X | O | | 패킷 손실 추적 | O | O | O | | 점진적 Ramp-up | X | X | O | | 지속시간 제한 | 무제한 | 무제한 | 설정 가능 | | 실시간 통계 | X | X | O (10초 주기) | | 퍼센타일 레이턴시 | X (평균만) | X | O (P50/P95/P99) | | CSV 내보내기 | X | X | O | | CLI 인자 | X | X | O | | 최악 클라이언트 분석 | X | X | O (상위 5) | --- ## 6. 구현 진행도 ### 완료 | 항목 | 상태 | 설명 | |------|:----:|------| | Echo RTT 측정 | **완료** | seq 기반 ping/pong, Stopwatch 고정밀 타이머 | | 더미 이동 시뮬레이션 | **완료** | 벽 충돌, 랜덤 방향 전환, 델타 타임 기반 이동 | | 맵 경계 처리 | **완료** | MapBounds (Clamp, 벽 반대 방향 계산) | | 패킷 손실 추적 | **완료** | LiteNetLib.NetStatistics 활용 | | 크래시 덤프 | **완료** | Debug: .log / Release: .log + .dmp | | 로깅 (콘솔+파일) | **완료** | Serilog 타임스탬프별 로그 파일 | | Graceful Shutdown | **완료** | Ctrl+C → CancellationToken → 통계 출력 후 종료 | | 스트레스 테스트 | **완료** | Ramp-up, 퍼센타일, CSV, CLI 인자 | | CLI 인자 지원 | **완료** | `stress -c N -d T --ip --port` | ### 미구현 / 향후 작업 | 항목 | 상태 | 설명 | |------|:----:|------| | 채널 입장 시뮬레이션 | 미구현 | INTO_CHANNEL 패킷 전송 후 게임 루프 진입 | | 전투 액션 시뮬레이션 | 미구현 | ACTION_PLAYER (공격/스킬) 패킷 전송 | | 상태 변경 시뮬레이션 | 미구현 | STATE_PLAYER (HP/MP) 패킷 전송 | | JWT 토큰 인증 테스트 | 미구현 | ACC_TOKEN 방식 인증 플로우 검증 | | 서버 응답 검증 | 미구현 | 수신 패킷 내용 파싱 및 정합성 체크 | | 테스트 시나리오 스크립트 | 미구현 | JSON/YAML 기반 테스트 시나리오 정의 | | 그래프 출력 | 미구현 | RTT/처리량 시계열 차트 생성 | --- ## 7. 설정 참고 ### 서버 연결 기본값 | 항목 | 값 | |------|-----| | IP | `localhost` | | Port | `9500` | | Connection Key | `test` | ### 이동 시뮬레이션 파라미터 | 항목 | 값 | 설명 | |------|-----|------| | moveSpeed | 3.5 | 이동 속도 (units/sec) | | 맵 범위 | -50 ~ 50 (X, Z) | 100x100 영역 | | 벽 감지 마진 | 0.5 | 벽 근처 판정 거리 | | 목표 거리 | moveSpeed x 3~12초 | 직진 후 방향 전환 | | 방향 전환 | 현재 ±30도 랜덤 | 벽 근처 시 반대 방향 강제 | ### 스트레스 테스트 기본값 | 항목 | 값 | 설명 | |------|-----|------| | 클라이언트 수 | 50 | `-c` 옵션 | | 지속 시간 | 60초 | `-d` 옵션 | | 전송 주기 | 100ms | `-i` 옵션 | | Ramp-up 간격 | 1000ms | `-r` 옵션 | | Ramp-up 배치 | 10명 | `-b` 옵션 | | 실시간 통계 주기 | 10초 | 고정 | | Echo 최대 pending | 500 | 메모리 누수 방지 |