[gRPC] C# gRPC 서버(Service) 샘플 만들어보기

728x90
반응형

 

 

들어가며

gRPC에 대한 내용을 간단하게 정리해봤으나, 실질적으로 동작하는 부분까지 확인을 직접 해보는게 좋을거 같아서 직접 프로젝트를 구성해봤습니다.

요즘의 서버는 다양한 개발환경으로 구성이 되어 있는데요. 각 서버간의 통신에 RESTFul API를 이용해서 구성하기도 하지만,  gRPC를 이용해서 보다 빠른 환경으로 구성할 수 있을 거 같네요. 

 

 

 

Service 프로젝트 만들기

새로운 프로젝트를 만들때, gRPC 서비스 템플릿을 이용해서 프로젝트를 생성 할 수 있습니다. 

 

 

 

 

이후 기본적인 위치 및 프로젝트 이름을 생성해서 프로젝트를 만들 수 있습니다. 

 

 

 

 

 

 

 

Client 프로젝트 만들기

클라이언트 프로젝트의 경우에는, 콘솔 어플리케이션 템플릿으로 생성 하였습니다. 

이후, 아래의 내용을 참고해서 Nuget Package 를 설치해주시면 됩니다. 

 

 

 

 

.proto 파일에 대한 C# 도구 지원

.proto 파일에서 C# 자산을 생성하려면 도구 패키지 Grpc.Tools가 필요합니다. 생성된 자산(파일)과 관련해서 다음 사항을 확인합니다.

  • 프로젝트를 빌드할 때마다 필요에 따라 생성됩니다.
  • 프로젝트에 추가되거나 소스 제어에 체크 인되지 않습니다.
  • obj 디렉터리에 포함된 빌드 아티팩트입니다.

 

서버 프로젝트의 경우에는 Grpc.AspNetCore 패키지가 포함되어 있고, 해당 패키지 안에 Grpc.Tools 에 대한 참조가 포함되어 있어서, 별도로 추가 할 필요는 없습니다. 

 

 

 

 

클라이언트 프로젝트의 경우에는 Grpc.Tools 가 따로 포함이 되어 있지 않기 때문에 Nuget.Package 에서 위 내용을 검색 후 설치해 주시면 됩니다. 

 

Install-Package Grpc.Net.Client
Install-Package Google.Protobuf
Install-Package Grpc.Tools

아니면 패키지 관리자 콘솔에서, Install-Package 해주세요~

 

 

 

 

 

 

 

 

Client 프로토콜 파일 추가

syntax = "proto3";

option csharp_namespace = "GrpcGreeterClient";

package greet;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply);
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings.
message HelloReply {
  string message = 1;
}

서버에서 정의한 proto 파일을 클라이언트에도 정의를 해줍니다. 

namespace 는 클라이언트에서 사용하도록 변경해주고요. 다른 부분은 동일하게 정의 합니다. 

 

 

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Google.Protobuf" Version="3.21.7" />
    <PackageReference Include="Grpc.Net.Client" Version="2.49.0" />
    <PackageReference Include="Grpc.Tools" Version="2.49.1">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>

    <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
    
  </ItemGroup>

</Project>

Client에서 생성한 파일은  빌드에 포함되지 않다보니, 추가적으로 프로젝트를 마우스 오른쪽 단추로 클릭하고 프로젝트 파일 편집을 선택합니다.

해당 파일을 Protobuf 속성을 사용해서 Include 해줍니다. 

 

 

 

 

 

클라이언트 코드 추가

using System;
using System.Threading.Tasks;
using Grpc.Net.Client;
using GrpcGreeterClient;

namespace GrpcSampleClient
{
    class Program
    {
        static async Task Main(string[] args)
        {
            using var channel = GrpcChannel.ForAddress("https://localhost:5001");
            var client = new Greeter.GreeterClient(channel);
            var reply = await client.SayHelloAsync(
                              new HelloRequest { Name = "GreeterClient" });
            Console.WriteLine("Greeting: " + reply.Message);
            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }
    }
}

클라이언트 코드는, gRPC 서버에 SayHello Method를 호출하도록 구성하였으며, Request 로 "GreeterClient" 를 인자로 넘기도록 구성된 샘플 코드를 사용하였습니다. 

그리고 Response 로 받은 내용을 찍어주는 심플한 코드입니다. 

 

 

 

 

 

서버 코드 추가

syntax = "proto3";

option csharp_namespace = "GrpcSampleService";

package greet;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply);
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings.
message HelloReply {
  string message = 1;
}

서버쪽 proto 파일입니다. namespace를 제외하고는 동일합니다. 

 

 

 

using Grpc.Core;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace GrpcSampleService
{
    public class GreeterService : Greeter.GreeterBase
    {
        private readonly ILogger<GreeterService> _logger;
        public GreeterService(ILogger<GreeterService> logger)
        {
            _logger = logger;
        }

        public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
        {
            return Task.FromResult(new HelloReply
            {
                Message = "Hello " + request.Name
            });
        }
    }
}

서버쪽 코드는 샘플 예제를 참조하였으며, Request 로 들어온 이름에 "Hello " 텍스트를 붙여서 Response 해줍니다. 

 

 

 

 

 

결과

gRPC 서버를 먼저 시작해줍니다. 

 

 

 

 

이후 클라이언트를 실행했으며, 서버로 부터 받은 Response 데이터를 정상적으로 출력해주고 있습니다. 

 

 

 

서버쪽으로도, 요청이 들어온 Log가 정상적으로 보여지네요.

간단한 샘플 코드를 이용해서, 다양하게 활용하면 좋을 거 같습니다. 

 

 

 

 

 

 

 

 

END


 

 

 

 

728x90