서비스
교육 철학

Networking and I/O (네트워킹 & 입출력)

Abstract

📌
게임이 바깥 세상과 주고받는 통로는 네 가지입니다. 무엇을 주고받느냐에 따라 고르면 됩니다. 넷 다 "요청을 넣으면 번호(serialId)를 돌려주고, 결과는 나중에 이벤트로 온다"는 같은 모양이라 하나를 익히면 나머지도 같은 방식으로 씁니다.
무엇을 쓸지 고르기
하고 싶은 일
모듈
예
서버 API 를 한 번 호출하고 응답 받기
WebRequest
랭킹 등록, 로그인, 공지 가져오기
파일을 내려받아 디스크에 저장
Download
추가 콘텐츠, 리플레이 파일
서버와 연결을 유지하며 계속 주고받기
Network
실시간 멀티플레이, 채팅
여러 파일을 하나로 묶어 읽고 쓰기
FileSystem
수천 개의 작은 파일을 한 덩어리로 배포
싱글플레이 게임에 온라인 기능을 얹는다면 십중팔구 WebRequest 하나면 충분합니다.
직접 해 보기 — 최고 점수를 서버에 올리기
public class ScoreUploader { private int mRequestId; public void Upload(string playerName, int score) { EventComponent events = GameEntry.GetComponent<EventComponent>(); events.Subscribe(WebRequestSuccessEventArgs.EventId, OnSuccess); events.Subscribe(WebRequestFailureEventArgs.EventId, OnFailure); WWWForm form = new WWWForm(); form.AddField("name", playerName); form.AddField("score", score); // 요청을 넣으면 번호가 돌아온다. 이 번호로 "내 요청의 응답"을 가려낸다 mRequestId = GameEntry.GetComponent<WebRequestComponent>().AddWebRequest("https://example.com/api/scores", form); } private void OnSuccess(object sender, GameEventArgs e) { WebRequestSuccessEventArgs ne = (WebRequestSuccessEventArgs)e; if (ne.SerialId != mRequestId) return; string body = Utility.Converter.GetString(ne.GetWebResponseBytes()); Log.Info("등록 완료: {0}", body); } private void OnFailure(object sender, GameEventArgs e) { WebRequestFailureEventArgs ne = (WebRequestFailureEventArgs)e; if (ne.SerialId != mRequestId) return; Log.Warning("등록 실패: {0}", ne.ErrorMessage); } }
C#
복사
이벤트는 전역으로 발행됩니다. 다른 코드가 넣은 요청의 응답도 같은 핸들러로 들어오므로, SerialId 비교를 빼면 남의 응답을 자기 것으로 처리하게 됩니다. 다 쓴 뒤에는 Unsubscribe 로 구독을 풀어야 합니다.
ToyboxNightmare 에서는
네 모듈 모두 쓰지 않습니다. 싱글플레이 오프라인 게임이기 때문입니다. GameFramework.prefab 에 컴포넌트는 붙어 있지만 요청이 없으면 아무 일도 하지 않습니다.
⚠️
이 에디션에서 다른 점 · 본문을 읽을 때 주의할 점
•
결과는 downloadComponent.DownloadSuccess += ... 같은 C# 이벤트가 아니라 EventComponent 구독으로 받습니다. 본문 예제도 그렇게 고쳐 두었습니다.
•
AddDownload 의 인자 순서는 (저장 경로, 주소) 입니다. 반대로 쓰기 쉽습니다.
•
Network 는 TCP 만 지원합니다(ServiceType.Tcp, TcpWithSyncReceive). UDP 는 없습니다. 또 패킷을 어떻게 자르고 직렬화할지는 프레임워크가 정해 주지 않습니다 — INetworkChannelHelper 를 직접 구현해야 연결할 수 있습니다.
•
FileSystem 은 일반적인 "파일 읽기/쓰기 유틸"이 아니라 가상 파일 시스템입니다. 여러 파일을 하나의 큰 파일 안에 넣어 관리합니다. 세이브 파일 하나를 쓰는 용도라면 File.WriteAllText 나 Setting 모듈이 맞습니다.
•
5절의 DefaultLoadResourceAgentHelper / DefaultResourceHelper 는 원작의 AssetBundle 로더입니다. 이 에디션에는 없고 Addressables 가 그 일을 합니다.
•
WebGL 빌드에서는 브라우저 제약으로 TCP 소켓을 쓸 수 없어 Network 모듈이 동작하지 않습니다.

📡 Networking and I/O (네트워킹 & 입출력)

1. 아키텍처 개요

•
Component-Helper 구조
→ Unity 컴포넌트가 매니저 기능을 노출, 실제 구현은 Helper 클래스가 담당
•
주요 구성:
◦
NetworkComponent : 네트워크 채널 관리 (TCP)
◦
DownloadComponent : 파일 다운로드 관리
◦
WebRequestComponent : HTTP/HTTPS 요청 처리
◦
ResourceHelper : 원격/로컬 리소스 로드
◦
FileSystem : 파일 읽기/쓰기

2. Network System

•
특징
◦
TCP 소켓 통신
◦
다중 채널(NetworkChannel) 구조
◦
하트비트(heartbeat) 내장
◦
패킷 직렬화/역직렬화 가능
◦
연결 상태 및 에러 이벤트 지원
•
핵심 API
◦
CreateNetworkChannel(name, serviceType, helper)
◦
GetNetworkChannel(name)
◦
DestroyNetworkChannel(name)
•
이벤트
◦
NetworkConnected
◦
NetworkClosed
◦
NetworkMissHeartBeat
◦
NetworkError
•
디버깅
◦
런타임 Debugger 창의 Network 탭 : 연결 상태, 송수신 패킷 수, 하트비트 상태 표시 (원작의 NetworkComponentInspector 는 이 에디션에 없음)

3. Download System

•
특징
◦
파일 다운로드 (전체, 부분, 범위 지정 지원)
◦
진행 상황 & 오류 이벤트 제공
•
Agent Helpers
◦
UnityWebRequestDownloadAgentHelper (최신 Unity API)
◦
WWWDownloadAgentHelper (Unity 2018.3 미만 전용. 현재 Unity 에서는 컴파일에서 제외됨)
•
주요 이벤트
◦
UpdateBytes, UpdateLength, Complete, Error

4. Web Request System

•
특징
◦
GET, POST 지원
◦
JSON, FormData, RawData 전송 가능
◦
이벤트 기반 완료/에러 처리
•
구현체
◦
UnityWebRequestAgentHelper

5. Resource Loading with Network I/O

•
DefaultLoadResourceAgentHelper
◦
AssetBundle 로드 (로컬/원격)
◦
바이트 스트림 처리
◦
에셋 추출
•
DefaultResourceHelper
◦
URL에서 바이트 읽기
◦
씬 언로드, 리소스 해제 기능 포함

6. File System

•
기능
◦
파일 읽기/쓰기
◦
디렉토리 관리
◦
커스텀 파일 시스템 확장 가능
•
통합
◦
리소스 시스템과 연결
◦
데이터 테이블 로딩 가능

7. 프레임워크 통합

•
Resource System : 원격 에셋 다운로드 활용
•
Event System : 모든 네트워크/IO 결과를 이벤트로 발행
•
Data Tables : 원격 데이터 테이블 로드 가능

8. 코드 예시

✅ 네트워크 연결
var networkComponent = GameEntry.GetComponent<NetworkComponent>(); var channel = networkComponent.CreateNetworkChannel("GameServer", ServiceType.Tcp, new GameNetworkChannelHelper()); channel.Connect(IPAddress.Parse("192.168.1.1"), 8888); channel.Send(gamePacket); channel.Close();
C#
복사
✅ 파일 다운로드
var downloadComponent = GameEntry.GetComponent<DownloadComponent>(); var events = GameEntry.GetComponent<EventComponent>(); // 결과는 C# 이벤트가 아니라 EventComponent 로 온다 events.Subscribe(DownloadSuccessEventArgs.EventId, OnDownloadSuccess); events.Subscribe(DownloadFailureEventArgs.EventId, OnDownloadFailure); // 인자 순서 주의: (저장할 경로, 내려받을 주소) string savePath = Path.Combine(Application.persistentDataPath, "bundle.dat"); mDownloadId = downloadComponent.AddDownload(savePath, "https://example.com/assets/bundle.dat"); private void OnDownloadSuccess(object sender, GameEventArgs e) { DownloadSuccessEventArgs ne = (DownloadSuccessEventArgs)e; if (ne.SerialId != mDownloadId) return; Debug.Log("Download completed: " + ne.DownloadPath); }
C#
복사
✅ 웹 요청
var webRequestComponent = GameEntry.GetComponent<WebRequestComponent>(); WWWForm form = new WWWForm(); form.AddField("username", "player"); form.AddField("score", 100); GameEntry.GetComponent<EventComponent>().Subscribe(WebRequestSuccessEventArgs.EventId, OnWebRequestSuccess); mRequestId = webRequestComponent.AddWebRequest("https://example.com/api/scores", form); private void OnWebRequestSuccess(object sender, GameEventArgs e) { WebRequestSuccessEventArgs ne = (WebRequestSuccessEventArgs)e; if (ne.SerialId != mRequestId) return; string response = Utility.Converter.GetString(ne.GetWebResponseBytes()); Debug.Log("Response: " + response); }
C#
복사
✅ 요약하자면:
•
네트워크 (TCP) : 채널 기반 소켓 통신
•
다운로드 : 파일 전송 및 범위 요청
•
웹 요청 : GET/POST API 호출
•
리소스 시스템 : (원작) AssetBundle + 네트워크 연동 — 이 에디션은 Addressables 가 담당
•
파일 시스템 : 기본 파일 I/O + 커스텀 확장