1. ABOUT ME 실제 현장의 문제를 자동화 시스템 구축으로 해결하며 백엔드 엔지니어로서의 첫 발을 내딛었습니다. 사업 현장의 운영 효율을 높이기 위해 프로세스 자동화 시스템을 직접 기획하고 개발했습니다. 웹 서버 설계, 데이터베이스 최적화, 클라우드 배포까지 전 과정을 주도하며 기술적 자산을 쌓았고, 이를 통해 '스스로 문제점을 발굴하고 끝까지 책임지는 개발 문화'의 중요성을 깨달았습니다.
불가능한 것은 없고, 자신의 능력이 부족한 것을 인정합니다 회의 중에 ‘가능할까요’라는 질문에 항상 ‘해보겠습니다’라고 대답합니다. 이후 구현을 위해 노력하고, ‘불가능한 것은 없다. 내가 못하는 것이다’라는 마음가짐으로 저의 지식 밖에서 구현을 위해 검색하고 배웁니다. 결과적으로 90% 이상은 구현에 성공했고, 더 많은 자신감과 끈기를 함양할 수 있었습니다.
2. SKILLS Language : Java, Python, Javascript, C++, C#
Backend : Spring Boot, Django, Node.js
Infra & DevOps: GCP Compute Engine, Linux, Nginx, Docker, Cloudflare
Database : MySQL
Tools : Git, GitHub
Others : Unreal Engine, Unity
3. PROJECT 합격뿌수기 | 2024.01. ~ 2026.07. (개인프로젝트) 개요: 실시간 동영상 강의 스트리밍 서비스와 질문/소통 게시판 플랫폼 기술 스택Infra & DevOps: GCP Compute Engine, Linux, Nginx, Gunicorn, Certbot(TLS), CloudFlare(Reverse Proxy) Database: Google Cloud SQL (MySQL 8.0) 상세 업무VPC Private IP를 이용한 네트워크 홉 레이턴시 개선과 직렬화 오버헤드 및 1+N 쿼리 문제 해결을 통한 Django ORM 최적화로 데이터 용량 45% 절감 및 API 응답 속도 97% 개선 GCP, Nginx, Gunicorn, systemd 데몬 기반의 무중단 배포 환경구축 및 Certbot(TLS), CloudFlare(Reverse Proxy) 연동을 통한 HTTPS 보안 강화 Django 서버 토큰 기반 유저 인증/인가 시스템 구현 및 RESTful API 설계·개발 Node.js 및 HLS 프로토콜 기반 동영상 스트리밍 서버 구축과 Toss Payments PG 결제 모듈 연동 githubhttps://github.com/mw08081/ha3pu
기술 설명 1. 백엔드 아키텍처 및 성능 최적화 1) API 설계 및 DB 쿼리 최적화(select_related, annotate)
2) API 설계 및 DB 쿼리 최적화(F 객체)
2. 데이터베이스 설계 및 인덱싱 최적화 1) DB 설계
구현 목표
정규화를 통해 데이터 중복을 최소화하고, 엔티티 간 무결성과 독립성을 확보한 데이터베이스 아키텍처 구축
설계 방법
User - Product (N:M 해소 및 데이터 스냅샷 보장) User와 Product 간 다대다(N:M) 관계를 교차 테이블인 Order로 해소하고, 구매 시점의 가격(final_price)을 별도 보관하여 원본 상품 정보 변경에도 과거 결제 데이터의 무결성을 유지Order - Payment (1:1 역할 분리 및 관심사 분리) 주문 본체 데이터와 PG 결제 데이터(Payment)를 1:1 (OneToOneField) 관계로 분리 설계하여, 결제 시도·실패·취소 등의 상태 변화 라이프사이클이 주문 본문 데이터를 오염시키지 않도록 관심사를 명확히 격리Order - Shipipng (최소 권한 기반의 데이터 보안 및 조회 최적화) 배송 발주 시스템에서 최소한의 데이터 테이블을 검색하고, 거래처 계정에 Shipping 테이블 조회 권한만 제공함으로써 데이터 패킷 최적화와 데이터베이스 보안을 향상
결과(일부 필드 생략)
2) DB 인덱싱 최적화
구현 목표
빈번하게 발생하는 필터링·정렬 조건에 최적화된 인덱스를 구성하여, DB CPU 사용량 절감 및 쿼리 응답 속도 최적화
구현 내용
User.email,Payment.payments_key (Unique Index)설계 이유: 고유 식별자 단건 조회 시 테이블 전체 검색을 방지하고 데이터 중복을 근본적으로 차단하기 위해 설정기대 효과: O(1) 수준의 조회 속도 확보 및 데이터 유일성(Uniqueness) 제약 강제class User(AbstractBaseUser, PermissionsMixin):
# 이메일 필드(필수, 검색)
email = models.EmailField(
unique=True
)
class Payment(models.Model):
# 결제 키 필드(검색, 결제취소)
payments_key = models.CharField(
max_length=200,
unique=True
)
Payment.payment_state + Payment.created_at ( Composite Index 복합 인덱스) 설계 이유: "특정 상태(예: 결제 대기)인 데이터 중 특정 기간 내 작성된 건"을 필터링하는 조건 검색 패턴에 최적화하기 위해 설정기대 효과: 단일 필드 인덱싱 시 발생하는 불필요한 레코드 스캔을 최소화하고, 결제 정산 및 상태 추적 배치(Batch) 쿼리 속도 극대화class Payment(models.Model):
STATE_CHOICES = [
('SUCCESS', '결제 완료'),
('WAITING_CANCEL', '취소 대기'),
('CANCELED', '취소 완료'),
]
# 결제 상태 (결제 완료, 취소 대기, 취소 완료)
payment_state = models.CharField(max_length=20, choices=STATE_CHOICES, default='SUCCESS')
# 거래 일시
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
indexes = [
# [복합 인덱스] 결제 상태별/기간별 내역 조회 최적화 (어드민 / 유저 결제 조회)
models.Index(fields=['payment_state', 'created_at'], name='idx_pay_state_created'),
]
3. 인프라 및 네트워크 설계 1) GCP 기반의 클라우드 인프라 구축
구현 목표
GCP 생태계를 활용하여 컴퓨팅, DB, 스토리지를 분리함으로써 서비스의 가용성 확보하고 안정적인 서버 운영 환경 구축
구현 내용
Compute Engine: Linux OS 기반 서버 구축 및 외부 고정 IP(Static IP) 할당을 통한 안정적인 서버 엔드포인트 운용 Cloud SQL: MySQL 8.0 기반으로 애플리케이션 서버와 DB를 분리하고, VPC 내부 IP 연동을 통해 외부 무단 접근 차단 및 네트워크 홉(Hop) 감소로 데이터 통신 성능과 비용 최적화 Cloud Storage: 정적 자원 및 유저 미디어 파일을 GCS 버킷으로 격리하여 서버 I/O 부담을 해소하고, 프라이빗 버킷에서 서명된 URL(Signed URL) 방식을 적용해 파일 보안 및 권한 검증 처리를 GCP 서비스로 이관 2) 웹 서버 및 네트워크 아키텍처 최적화
구현 목표
클라이언트와 애플리케이션 간 보안성 강화 및 WSGI/Reverse Proxy 레이어 구성을 통한 웹 요청 처리 성능 최적화
구현 내용
Nginx & Gunicorn: Nginx를 Reverse Proxy로 두어 정적 파일 처리 및 SSL 종단을 담당하게 하고, Unix Socket 연동 기반의 Gunicorn(WSGI)을 통해 Django 애플리케이션으로의 요청 동시성 효율화 Cloud Flare: DNS 타깃팅 및 Reverse Proxy모드를 적용하여 원천 서버 IP 노출을 차단하고 DDoS 등 외부 보안 위협 1차 방어
4. 시스템 및 인증 보안 1) Cloud SQL 데이터베이스 보안 및 감사 체계 구축
구현 목표
데이터베이스 레이어의 네트워크 격리, 전송 구간 암호화, 최소 권한 적용 및 감사 로그 체계를 구축하여 외부 데이터 침해 방지 및 시스템 추적성 강화
구현 내용
비공개 IP 전용 구성: Cloud SQL을 VPC 내부 전용 IP로 전환하여 공용 인터넷 노출을 차단 전송 구간 SSL/TLS 암호화 및 패킷 검증: 'ssl_mode': 'REQUIRED' 옵션 적용 'OPTIONS': {
'charset': 'utf8mb4',
'ssl': {
'ssl_mode': 'REQUIRED' # 데이터 전송 암호화 강제!
}
},sudo tcpdump -i any -X -vv port 3306
# 암호화 전
0x0240: 5f70 6466 1864 6f77 6e6c 6f61 645f 6578 _pdf.download_ex
# 암호화 후
0x0240: b032 6a20 e1a7 d2b2 2431 e14f 2db3 e01b .2j.....$1.O-...
최소 권한 원칙(Principle of Least Privilege) 계정 관리: 기존 root 접속 방식에서 탈피하여 서비스 전용 최소 권한 계정(django_user)으로 DB 인가 권한 제한 GCP Cloud Audit Logging 감사 체계 구축: DB 감사 플래그(cloudsql_mysql_audit = ON) 및 IAM 연동을 설정하고 Log Explorer 쿼리를 활용한 DML 추적 환경 구성감사 플래스 설정 상태 로그 탐색기에서 LQL 설정시 다음과 같은 내용을 확인할 수 있다 (현재 general_log를 통해서 검색) 2) Django 기본 토큰 기반 유저 인증
구현 목표
Django 기본 TokenAuthentication 구조를 활용하여 API 요청별 사용자 접근 권한 검증 강화
구현 내용
Django TokenAuthentication 적용: 유저 로그인 시 서버 단에서 고유 Token을 발급·매핑하고, HTTP Header를 통한 요청 검증 처리 RESTful API 권한 제어: @permission_classes([IsAuthenticated])를 활용해 보호된 엔드포인트에 대한 무단 접근 차단 코드
# 로그인 시, 토큰 생성 및 조회 후 Response로 돌려줌
token, _ = Token.objects.get_or_create(user=user)
return Response(
{
'user_id': user.id, 'token': token.key
},
status=status.HTTP_200_OK
)// 웹에서 request 시, header에 토큰을 담아서 전송
final response = await http.get(
Uri.https(ApiHelper.djangoServerApiAddr, '/user/getUser'),
headers: {
'Authorization': 'Token $token', // 토큰 헤더로 전달
},
);# 해더의 인증 토큰을 파싱하여 인증된 유저의 요청만 response하도록 데코레이터 설정
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def get_user(request):
# ..기타 예외 처리 생략..
# 헤더의 토큰으로 검증된 request.user 객체를 직렬화함
serializer = UserSerializer(request.user)
return Response(
serializer.data,
status=status.HTTP_200_OK
)
5. HLS 기반 미디어 스트리밍 서버 분리 구축 및 토스페이먼츠 PG 연동 1) Cloud SQL 데이터베이스 보안 및 감사 체계 구축
구현 목표
메인 웹 서버(Django)의 동영상 I/O 병목 현상을 방지하기 위해 비동기 처리 기반의 Node.js 스트리밍 전용 모듈 구축
구현 내용
Nginx 리버스 프록시 연동: 서브도메인으로 유입되는 HTTP 트래픽을 내부 HLS_SERVER_PORT 포트의 Node.js 서버로 전달하여 보안성 및 TLS 처리 분리 # 2. Nginx 설정
server {
server_name SUB_DOMAIN;
location / {
proxy_pass http://127.0.0.1:HLS_SERVER_PORT;
}
}
GCS 비공개 버킷 스트림 연동: 로컬 디스크 저장 방식 대신 @google-cloud/storage SDK를 통해 GCS 버킷 내 HLS 파일 존재 여부(exists)를 검증하고, 읽기 스트림(createReadStream)을 생성하여 서버 메모리 점유 최소화 // hls request 필터 및 파일 유무 확인
exists: async (req, cb) => {
if (!req.url.endsWith('.m3u8') && !req.url.endsWith('.ts')) { //.. 생략}
else {
// .. 중략
const [exists] = await storage.bucket(bucketName).file(filePath).exists();
if (exists) {
return cb(null, true); // 파일 유무 확인 후 플래그 반환
}
}
}// .ts 파일 반환 과정
getSegmentStream: (req, cb) => {
const filePath = req.url.substring(1);
const file = storage.bucket(bucketName).file(filePath);
const stream = file.createReadStream(); // 비동기 스트림 생성 (메모리 최적화)
// ..
cb(null, stream);
}
2) 토스페이먼츠 PG 연동
구현 목표
클라이언트-서버 간 금액 검증으로 결제 데이터 위변조를 차단하고, 실패 시나리오별 예외 처리를 통해 결제 트랜잭션의 무결성과 안정성을 확보
구현 내용
6번: 토스페이먼츠 API 스펙에 따라 결제 요청과 최종 승인(Confirm) 과정을 분리하여 처리 7번: 2번 과정에서 서버 DB에 저장한 주문 데이터(유저, 금액)와 6번에서 전달받은 결제 정보가 일치하는지 검증 (4번 클라이언트 단계에서의 금액 변조 차단)
코드
# get_payments_page 결제하기 버튼 클릭
@permission_classes([IsAuthenticated])
@xframe_options_exempt
def get_payments_page(request, orderID):
try:
context = {
# 구매자 정보, 금액
}
# ..생략..
return render(request, 'payments.html', context)// payments.html에서 requestPayment()를 호출
requestPayment();
async function requestPayment() {
try {
// ..requestPayment 준비과정 생략..
await tossPayments.payment({
customerKey,
}).requestPayment({
// .. 기타 파라메터 생략 ..
amount,
successUrl: successUrl.toString(), // 성공시 리다이렉트 될 주소
# 유저의 결제 요청과 함게 결제 성공 여부를 tosspayments api를 통해 확인
# 결제 성공 여부를 확정 짓는 API
@api_view(['POST'])
def confirm(request) :
try:
# 결제 유저 검증
# 결제 금액 검증
conn = http.client.HTTPSConnection("api.tosspayments.com")
# payload 생성
headers = {
'Authorization': encrypted_secret_key,
'Content-Type': "application/json"
}
conn.request("POST", "/v1/payments/confirm", payload_json, headers)
# 이후 response 에서 결제 확인이 되면
# 결제 성공 비즈니스 로직을 실행트러블 슈팅 1. 특정 조회 API 병목 개선 및 ORM 최적화(응답속도 97% 개선)
2. 토스페이먼츠 PG연동 간 발생한 CSRF 관련 웹 보안 문제
문제 상황
토스페이먼츠 결제창 인증 완료 후, 백엔드 승인 엔드포인트(/store/confirm)로 POST 요청 전송 시 403 Forbidden (CSRF verification failed) 에러가 발생하며 결제 승인 실패. 세션 기반 인증이 적용된 백엔드 환경에서 결제 승인 요청이 보안 미들웨어에 의해 차단됨
원인 분석
헤더 누락: POST 요청에 대해 브라우저 쿠키와 요청 헤더 CSRF 토큰을 교차 검증이 필요하지만, X-CSRFToken 헤더 누락으로 요청이 차단됨
// 토스페이먼츠 결제 완료 후 리다이렉트된 payments_success.html의 스크립트
const response = await fetch(`${window.location.origin}/store/confirm`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": csrftoken // X-CSRFToken 헤더 추가하여 CSRF 검증 통과
},
credentials: "include",
body: JSON.stringify(requestData),
});결과
웹 보안 및 CSRF 방어 메커니즘 이해: 쿠키 기반 웹 애플리케이션에서 POST 요청 시 왜 CSRF 토큰 검증이 필요한지, 헤더와 쿠키 간 교차 검증 구조를 이해함
3. 대용량 파일 처리 부하 개선: GCP Signed URL 기반 전송 책임 이관
문제 상황
두가지 서비스가 몰릴 경우 대용량 I/O와 수많은 네트워크 커넥션 발생으로 인해 서버 자원에 극심한 병목과 부하 발생
원인 분석
단일 인프라 내 리소스 처리 병목: 동일 Compute Engine 인프라 자원을 공유하는 구조에서 Node.js의 지속적인 HLS 조각 파일 스트리밍 요청과 Django 서버의 대용량 파일 다운로드 I/O가 동시에 몰려 CPU 및 Disk I/O 병목이 심화됨
시도
HLS 전용 Compute Engine 인스턴스 추가: HLS 서버를 다른 Comput Engine Instance로 분리하는 방법도 고민해봤지만, 클라우드 서비스 비용 부담 증가로 무리가 있음을 확인
해결 방법
GCP Cloud Storage Signed URL 도입: 클라이언트는 전달받은 Signed URL을 이용해 GCS에서 직접 파일 다운로드 def download_file(request, file_path):
# 유저 인증 및 다운로드 가능 여부 검증
# 서명된 URL 생성
signed_url = generate_signed_url(GCS_BUCKET_NAME , file_path)
# 사용자를 GCS로 리다이렉트
return HttpResponseRedirect(signed_url)def generate_signed_url(bucket_name, file_path, expiration=10):
# 파일 검색 및 url 생성 준비
# 서명된 URL 생성
return blob.generate_signed_url(
version="v4",
expiration=timedelta(seconds=expiration),
method="GET",
response_disposition=(
f'attachment; filename="{file_label}.{blob_extension}"; filename*=UTF-8\'\'{quote(file_label + "." + blob_extension)}'
)
)
결과
Compute Engine 부하 감소 : 대용량 파일 다운로드 책임을 GCS 인프라로 완전히 넘김으로써 Gunicorn Worker 스레드 점유와 Disk I/O 병목을 근본적으로 해결 보안성과 효율성의 양립: 다운로드 Url에 유효기간 방식을 더해 추가적인 보안성을 확보
네크로맨서 | 2026.01. ~ 2026.04. 개요: Steamworks API 기반의 리슨 서버 협동 멀티플레이어 게임 기술 스택: Unreal Engine(5.5.4), C++, Steamworks API 상세 업무Listen Server 기반 P2P 멀티플레이어 세션 및 WAN 네트워크 환경 구축 관전 시스템 개발 및 호스트-클라이언트 간 상태 동기화 githubhttps://github.com/mw08081/necromancer
기술 설명 구축 관전시스템 패킷 전송 주기 조절 (및 프로파일링) 트러블 슈팅
로얄 치킨 | 2025.09. ~ 2025.12. 개요: Steamworks API 기반의 데디케이티드 서버 탑다운 배틀로얄 게임 기술 스택: Unreal Engine(5.5.4), C++, Steamworks API 상세 업무Steamworks API를 연동하여 실시간 UDP 통신 기반의 WAN 멀티플레이어 환경 및 중앙 서버 아키텍처 구축(데디케이티드 서버) 중앙 서버 권한 기반의 실시간 데이터 동기화 구현 및 매치메이킹 세션 검증을 통한 유저 인메모리 세션 관리 서버 패킷 플로딩 공격에 대비한 패킷 수신 주기 제어 및 비정상 유저 강제 세션 종료 로직 개발 githubhttps://github.com/mw08081/RoyalChicken
기술 설명 1. 실시간 UDP WAN 네트워크 기반의 중앙(데디케이티드) 서버 아키텍처 구축
2. 중앙 서버의 실시간 데이터 동기화 및 인메모리 관리
구현 목표
서버 정보 동기화: 중앙 서버 중심의 플레이어 상태 관리로 유저 간 데이터 오차 및 변조 방지 인메모리 세션 라이프사이클 관리: 유저 입/퇴장 및 세션 정보의 빠른 인메모리 처리
구현 내용
PostLogin()을 통해 들어온 유저의 정보를 확인하고 세션 정보를 관리함
void ARCWaitingLvGameModeBase::PostLogin(APlayerController* NewPlayer)
{
Super::PostLogin(NewPlayer);
ARCPlayerController* NewPlayerController = Cast<ARCPlayerController>(NewPlayer);
if (NewPlayerController != nullptr)
{
// SeverTravel을 위한 컨트롤러 인스턴스 메모리 저장
LogInPlayerControllers.Add(NewPlayerController);
// 게임시작을 위한 최소 인원 확인
if (LogInPlayerControllers.Num() >= MinPlayerCount) {
URCGameInstance* RCGameInstance = GetWorld()->GetGameInstance<URCGameInstance>();
if (IsValid(RCGameInstance))
{
// 세션 시작
RCGameInstance->ManageSession(true);주기적으로 게임 정보를 업데이트하고 이를 접속한 플레이어들에게 전달하여(멀티케스트) 게임 정보 및 게임 메시지를 동기화함 // 1초 단위로 게임 정보 갱신
GetWorld()->GetTimerManager().SetTimer(MainTimerHandle, this, &ThisClass::OnMainTimerElapsed, 1.f, true);
// 게임 정보 갱신 함수 일부
ARCGameStateBase* RCGameState = GetGameState<ARCGameStateBase>();
if (IsValid(RCGameState))
{
RCGameState->AlivePlayerControllerCount = LogInPlayerControllers.Num();
}// 접속 인원 정보 수신 시, 델리게이트 호출
void ARCGameStateBase::OnRep_AlivePlayerControllerCount()
{
OnAlivePlayersChanged.Broadcast(AlivePlayerControllerCount);
}
// 게임 메시지 정보 수신 시, 게임 내 ui 게임 메시지 수정
void ARCGameStateBase::OnRep_ReplicatedGameModeDelay()
{
FString NotiMsg;
switch (MatchState)
{
case EMatchState::None:
break;
case EMatchState::Waiting:
NotiMsg = FString::Printf(TEXT("게임 시작까지 %d초"), ReplicatedGameModeDelay);
결과
새로운 유저 세션 접속
최소 플레이어 수 만족으로 세션 시작
3. 실시간 상태 변화 및 애니메이션 멀티캐스트 복제
구현 목표
실시간 액션 동기화: Server RPC 기반의 유저 액션 처리 및 상태/애니메이션 복제(Replication)
구현 내용
유저 액션에 따른 Server RPC 실행을 통해 게임정보 및 애니메이션 동기화 // 자신의 애니메이션 실행
// 클라이언트 일 경우
if (!HasAuthority())
{
// Server RPC 호출
Server_StartAttack(TargetWorldPos);
return;
}// Server RPC 실행
void AWeaponBase::Server_StartAttack_Implementation(const FVector_NetQuantize& TargetWorldPos)
{
CachedTargetWorldPos = TargetWorldPos;
bWantsToAttack = true;
AttackAccum = GetAttackInterval();
// 애니메이션 실행 및 주변 플레이어에게 브로드케스팅 ..
결과
공격에 따른 서버 로그 및 애니메이션 복제 ↑ 공격자 화면 / ↑ 피해자 화면
4. 디도스/패킷 플로딩 방어 및 비정상 유저 강제 세션 종료 로직 구현
구현 목표
악의적으로 과도한 패킷 송신(Packet Flooding)을 유발하는 유저를 퇴장 처리시키는 로직
구현 내용
Rate Limiting (수신 주기 제어): 유저별 패킷 수신 주기 패킷 검증 // 최대 패킷 레이트를 설정할 수도 있음
[/Script/Engine.NetDriver]
net.MaxPacketRate=50
bEnablePacketRPCThrottling=Truevoid ARCPlayerCharacter::Server_FloodTest_Implementation()
{
ServerTestPacketCount++;
if (ServerTestPacketCount > MAX_PACKET_RATE)
{
APlayerController* PC = Cast<APlayerController>(GetController());
if (PC)
{
UE_LOG(LogTemp, Error, TEXT("!!! FLOOD DETECTED: KICKING CLIENT !!!"));
// 1. 클라이언트 처리: Client RPC 전송
Client_ForceQuitGame();
// 1. 서버처리: 클라이언트에게 킥 사유를 보내고 메인 화면/접속 해제 처리
PC->ClientWasKicked(FText::FromString(TEXT("Packet Flooding Detected")));
// 2. 서버처리: 네트워크 소켓 세션 즉시 단절
if (PC->GetNetConnection())
{
PC->GetNetConnection()->Close();// Client에서 킥처리(클라이언트 화면 종료)
void ARCPlayerCharacter::Client_ForceQuitGame_Implementation()
{
APlayerController* PC = Cast<APlayerController>(GetController());
if (PC)
{
UKismetSystemLibrary::QuitGame(GetWorld(), PC, EQuitPreference::Quit, false);
}
}
결과
어뷰징으로 킥 당하는 유저 (우측 유저)
트러블 슈팅 1. Steamworks api 기반의 게임 세션 생성 시, 클라이언트에서 세션 검색 불가
문제 상황
데디케이티드 서버(Dedicated Server) 프로세스를 정상적으로 실행 및 초기화하였으나, 클라이언트 측에서 게임 세션을 검색할 수 없는 현상 발생
원인 분석 및 가설 검증
가설 1: 세션 식별자(Session Name) 및 세션 설정 문제검증: 세션 이름의 유일성(Uniqueness) 미보장 또는 설정 오류로 인해 검색이 안 되는 것으로 추정하여 세션 생성 및 검색 파라미터를 수정하였으나, 여전히 세션이 검색되지 않음 OnlineSessionInterface->OnCreateSessionCompleteDelegates.AddUObject(this, &URCGameInstance::OnCreateSessionComplete);
// 세션 설정 정보 재확인
TSharedPtr<FOnlineSessionSettings> SessionSettings = MakeShareable(new FOnlineSessionSettings());
SessionSettings->bIsLANMatch = false; // Steam Server이므로 LanMatch = false
SessionSettings->NumPublicConnections = 4;
SessionSettings->bAllowJoinInProgress = true;
SessionSettings->bAllowJoinViaPresence = true;
SessionSettings->bShouldAdvertise = true; // 세션 생성 후, 세션 정보 어드버타이징 = true
SessionSettings->bUsesPresence = true;
SessionSettings->bIsDedicated = true; // 세션 종류이므로 dedicated = true
// 세션 검색에 필요한 별도의 Key 값 (SessionName) 생성하여 검색 -> 실패..
SessionSettings->Set(FName(TEXT("SessionName")), FString(TEXT("DedicatedServer Session")), EOnlineDataAdvertisementType::ViaOnlineServiceAndPing);
SessionSettings->Set(FName(TEXT("SessionStart")), false, EOnlineDataAdvertisementType::ViaOnlineServiceAndPing);
OnlineSessionInterface->CreateSession(0, FName(TEXT("DedicatedServer Session")), *SessionSettings);
가설 2: 네트워크 포트 바인딩 및 통신 블로킹 문제검증: 세션 검색 결과 개수를 로그로 출력하여 세션 정보 수집 여부를 확인하던 중, 서버와의 통신 자체가 차단되고 있음을 인지 void ATitlePlayerController::OnFindSessionComplete(bool bWasSuccessful)
{
if (!OnlineSessionInterface.IsValid() || !bWasSuccessful)
{
return;
}
// 해당 로그에서 세션 수가 0으로 출력됨
UE_LOG(LogTemp, Error, TEXT("Found Session Count : %d"), SessionSearch->SearchResults.Num());
원인: 로컬(집) 환경에서 데디케이티드 서버를 호스팅하면서 서버 기본 포트(27015)가 외부로 열려있지 않아 클라이언트의 패킷 요청이 차단됨
해결방법
포트포워딩(Port Forwarding) 설정: 공유기 및 방화벽 설정에서 데디케이티드 서버가 사용하는 통신 포트(27015 / UDP)를 개방하고 서버 호스트 PC로 포워딩 처리 결과
실제 STEAM 글로벌 서버에서 생성한 게임 세션을 확인할 수있음 패킷을 수신할 수 없을 경우 방화벽과 포트 개방 여부를 확인해볼 수 있다는 점을 배움
2. Packet Flooding으로 인한 플레이어 킥 이후, 피격된 플레이어의 상태 정보 롤백
문제 상황
어뷰저 클라이언트은 Packet Flooding판정으로 킥(Kick)되었으나 이미 서버에 먼저 도착한 패킷으로 인해 타겟 플레이어의 체력이 감소하는 문제 발생
롤백 시도 및 한계
시도데미지 역산 (ApplyDamage에 음수값 전달): 데미지 계산식(방어력 계산 등)을 재경유하면서 정확한 체력 복구가 불가능함을 확인 이전 체력 스냅샷(Snapshot) 복원: 킥 발생 시 피격 대상의 체력을 롤백하려 했으나, 정상적인 다른 플레이어의 공격과 어뷰징 공격이 같은 프레임에 섞여 들어올 경우 정확한 '어뷰징 피격분'만 발라내어 복구하기 어려움 확인. 뿐만 아니라 체력 이외의 별도의 모든 특성에 스냅샷을 도입해야하는 어려움 확인 해결방법
엔진 기본 기능 중에 클라이언트의 요청이 정상적인 요청인지 검사 후 실행하는 방식인 _Validate 함수 구현 // ARCPlayerCharacter.h
UFUNCTION(Server, Reliable, WithValidation)
void Server_Attack()// ARCPlayerCharacter.cpp
bool ARCPlayerCharacter::Server_Attack_Validate()
{
ServerTestPacketCount++;
// 어뷰징이 확인될 경우
if (ServerTestPacketCount > MAX_PACKET_RATE)
{
UE_LOG(LogTemp, Error, TEXT("!!! FLOOD DETECTED IN VALIDATION: KICK CLIENT !!!"));
return false;
}
return true; // 정상 요청
}
void ARCPlayerCharacter::Server_Attack_Implementation()
{
// 데미지 계산 및 적용
ApplyDamage(...);
}
결과
Server RPC 호출 시 서버 측에서 _Validate → _Implementation 순으로 처리되는 엔진 라이프사이클을 학습함 어떠한 처리이든지 트랜잭션 처리 전 “선 검증, 후 실행”의 중요성을 깨달음
때려쳐: 샷건 시물레이터 | 2023.11 ~ 2025.06 개요: 사실적인 사물 표현과 물리 파괴 기반의 3D 액션 시뮬레이션 게임 기술 스택: Unreal Engine 5.3.2 상세 업무: Chaos destruction 기반 파손 액터 구현 및 질량 연산(Impulse)을 활용한 물리 시뮬레이션 개발 githubhttps://github.com/mw08081/projectD
갈바닉브라이드 | 2022.04 ~2023.09 개요: 갈바니즘 이론을 주된 기믹으로 스테이지를 클리어하는 잠입, 퍼즐, 액션 게임 기술 스택: Unity (2020.3.30f1) 상세업무: 삼각함수·내적·재귀 알고리즘 기반 기믹 연산 개발과 게임 플레이 최적화 githubhttps://github.com/mw08081/Modern_Prometheus
4. EDUCATION & TRAINING 스파르타코딩클럽 내일배움캠프 언리얼 트랙 | 2025.07 ~ 2026.04 Unreal Engine 5 및 C++ 기반 게임 개발/서버 교육 과정 이수 가천대학교 컴퓨터공학과 | 2018.03 ~ 2024.02
5. ACTIVITIES 부산 인디게임 페스티벌(BIC) | 2023.08 ~ 2023.08 It's Alive 팀의 '갈바닉브라이드' 출품 및 전시 부스 운영 현장 유저 플레이 데이터 및 피드백 수집을 통해 사용자 경험(UX) 개선점 발굴 넥슨 게임잼: 재밋넥 | 2023.07 ~ 2023.07 3명의 클라이언트 프로그래머와의 게임 개발을 진행하면서 의사소통과 역할분배를 통한 팀워크 발휘 게임메이커스 6기 | 2022.04 ~ 2023.03 대학생 게임 개발 동아리에서 It’s Alive팀으로 활동 다양한 사람들과 소통하며 처음으로 협력하여 게임 개발 다른 사람들이 바라보는 나의 단점도 듣고, 상충되는 의견 조율에 필요한 화법에 대해 고민해볼 수 있는 시간이 가짐