포스트

유니티에서 gRPC 사용하기 4 - 클라이언트 구성과 코드 생성

Unity에서 gRPC 클라이언트(YAHH) 구성, NuGetForUnity, proto 코드 생성 흐름

유니티에서 gRPC 사용하기 4 - 클라이언트 구성과 코드 생성

개요

이전 글에서 서버(ASP.NET Core gRPC + MySQL/Dapper)를 만들어 보았다. 이번에는 유니티 클라이언트에서 gRPC를 실제로 호출하기 위해 환경을 준비하고, proto를 C#으로 뽑아낸 다음 채널/핸들러를 붙여서 간단히 요청까지 보내보았다.

업데이트 (2025-09-24)

이 글을 포스팅하는 오늘 날짜 기준으로, 유니티 코리아 공식 유튜브에서 관련 언급이 있었다. Unity 6.3 Beta부터 HTTP/2 지원이 추가된다고 밝혔다. 다만 이 지원이 엔진 내부의 어떤 계층까지 포함되는지는 아직 명확하지 않아, 현시점에서 YetAnotherHttpHandler(YAHH)를 완전히 대체할 수 있을지는 미지수다.

Unity Korea Official Youtube Http/2 지원 자료 사진

1) 패키지 설치

먼저 HTTP/2 통신을 위한 YAHH(YetAnotherHttpHandler)와 ProtoBuf를 설치하기위한 NuGet 패키지를 설치해주었다.

일단 NuGet에서는 아래의 4개 패키지를 설치해 주어야한다.

Unity에서 gRPC를 사용하기위한 기본 Pakcage 구성

  • Grpc.Net.Client
  • Google.Protobuf
  • Grpc.Tools
  • System.IO.Pipelines

protoc 컴파일러는 Grpc.Tools 안에 들어있다.

2) Unity에서 proto 코드 생성 흐름

일반적인 Visual Studio 환경에서는 MSBuild가 proto 변경을 감지해서 자동으로 C# 코드를 만들어 준다. 그런데 Unity는 MSBuild 파이프라인이 아니라서 수동으로 protoc를 호출해야 한다.

그래서 커뮤니티에서는 이를 어떤방식으로 해결을 했을까가 궁금해서 검색을 해보았다. 배치 파일로 매번 실행을 하거나, 아에 유니티 툴로 만든 오픈소스를 사용하는게 주를 이루었다. 그런데 배치 파일은 매번 파일 탐색기에서 클릭을 해야하고, 오픈소스 툴은 너무 불편하게 만들어 놓았기 때문에 그냥 내가 쓰기 편하게 툴을 하나 만들었다.

ProtoBuilderForUnity - GitHub

Unity 에서 protoc에게 C# 코드 생성을 요청하는 Custom Tool 예제 사진

단축키 “Ctrl + L”로 서버의 .proto를 가져와 Unity 프로젝트 안의 Grpc.Tools(protoc)에 명령을 전달해서 C# 클래스를 생성한다. 서버 프로젝트가 여러 개인 것도 생각해서 소스 경로를 여러 개로 나눠서 관리할 수 있게 해두었다.

최초 한 번 경로만 잡아두면 이후에는 단축키로 계속 수동 컴파일을 돌리면 된다. 잘 되면 아래처럼 C# 코드가 생성된다.

Unity에서 Custom Tool로 Protoc에게 코드 생성을 요청한 결과 사진

3) 간단한 로그인 UI

간단하게 로그인 UI를 만들어보았다.

Unity에서 간단하게 만든 Login UI 사진

Unity에서 간단하게 만든 Register UI

4) 채널/핸들러 초기화(YAHH + Grpc.Net.Client)

코드 초기화를 한번 알아보면, 핵심은 목적지와 연결통로에 대한 추상화인 Channel에 YAHH를 넘겨주면 된다는 거다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private GrpcChannel _channel;
private AccountsClient _client;
private YetAnotherHttpHandler _httpHandler = new YetAnotherHttpHandler { Http2Only = true };

private void Awake()
{
    // HTTP/2 설정
    AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2Support", true);
    AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

    // 서버 주소 설정
    string address = ServerAddress;
    if (string.IsNullOrEmpty(address) == false)
    {
        if (address.StartsWith("http", StringComparison.OrdinalIgnoreCase) == false)
        {
            address = $"http://{address}";
        }
    }
    else
    {
        address = "http://localhost:7777";
    }

    var channelOptions = new GrpcChannelOptions
    {
        DisposeHttpClient = true,
        HttpHandler = _httpHandler
    };

    _channel = GrpcChannel.ForAddress(address, channelOptions);
    _client = new AccountsClient(_channel);
}

5) 회원가입 요청 예시

이제 생성된 클래스를 이용해 간단하게 요청을 보내봤다. 아래는 회원가입 예시다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/// <summary>
/// 회원가입
/// </summary>
public async Task<RegisterResponse> RegisterAsync(string username, string password)
{
    if (string.IsNullOrEmpty(username))
        throw new ArgumentException("username");

    if (string.IsNullOrEmpty(password))
        throw new ArgumentException("password");

    var request = new RegisterRequest
    {
        Username = username,
        Id = username,
        Password = password
    };

    try
    {
        var response = await _client.RegisterAsync(request);
        return response;
    }
    catch (Grpc.Core.RpcException)
    {
        throw;
    }
}

서버에서는 입력을 검증한 뒤 사용자 정보를 DB에 저장한다(비밀번호는 서버 쪽에서 해시). 테스트해 보니 아래처럼 응답이 잘 왔다.

MySQL 데이터베이스에 요청한 회원가입에 대한 User Data Table 사진

마무리

일단 로그인은 여기까지만 작업을 해볼까 하다가, JWT로 인증 토큰을 발급하고 유효기간까지 확인하는 흐름도 한번 해봐야겠다는 생각이 들었다. 그래서 이 부분은 다음 포스팅에서 다루겠다.

참고자료

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.