이전 포스팅에이서 gRPC 를 이용해 Streaming Server 를 만들어 Client 간 통신하는 예제입니다.
1. ASP.NET Core gRPC 서비스 프로젝트를 생성합니다.
2. proto 파일을 정의합니다. (weather.proto)
요청구조는 없고 api 호출시 WeatherData 를 반환합니다.
returns 인자로 stream WeatherData 로 정의되었습니다.
syntax = "proto3";
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
option csharp_namespace = "GrpcStreamServer";
package WeatherForecast;
// The weather service definition.
service WeatherForecasts {
// Sends a weatherStream
rpc GetWeatherStream (google.protobuf.Empty) returns (stream WeatherData);
}
message WeatherData {
google.protobuf.Timestamp dateTimeStamp = 1;
int32 temperatureC = 2;
int32 temperatureF = 3;
string summary = 4;
}
3. WeatherService.cs 에 동작을 정의합니다.
날짜별 온도값을 랜덤 하게 생성하여 20개를 보냅니다.
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using GrpcStreamServer;
using static GrpcStreamServer.WeatherForecasts;
namespace GrpcStreamServer.Services
{
public class WeatherService : WeatherForecastsBase
{
private readonly ILogger<WeatherService> _logger;
public WeatherService(ILogger<WeatherService> logger) => _logger = logger;
public override async Task GetWeatherStream(Empty _, IServerStreamWriter<WeatherData> responseStream, ServerCallContext context)
{
var rng = new Random();
var now = DateTime.UtcNow;
var i = 0;
while (!context.CancellationToken.IsCancellationRequested && i < 20)
{
await Task.Delay(500); // Gotta look busy
var forecast = new WeatherData
{
DateTimeStamp = Timestamp.FromDateTime(now.AddDays(i++)),
TemperatureC = rng.Next(-20, 55),
Summary = ""//Summaries[rng.Next(Summaries.Length)]
};
_logger.LogInformation("Sending WeatherData response");
await responseStream.WriteAsync(forecast);
}
}
}
}
4. Program.cs 에서 WeatherService Mapping 코드를 추가합니다.
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<WeatherService>();
});
using GrpcStreamServer.Services;
var builder = WebApplication.CreateBuilder(args);
// Additional configuration is required to successfully run gRPC on macOS.
// For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
// Add services to the container.
builder.Services.AddGrpc();
var app = builder.Build();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<WeatherService>();
});
// Configure the HTTP request pipeline.
//app.MapGrpcService<WeatherService>();
app.Run();
5. Properties 의 launchSettings.json 파일에 서비스 주소 정의 및 기타 옵션을 설정합니다.
{
"profiles": {
"GrpcStreamServer": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "http://localhost:5038;https://localhost:7038",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
6. appsettings.json 파일에서 Protocols 정의 및 Log Level 지정
Protocols 에 http2 로 설정합니다.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Kestrel": {
"EndpointDefaults": {
"Protocols": "Http2"
}
}
}
7. appsettings.Development.json 파일에서 Develope 모드 일 때 Info 도 로그가 찍히도록 Log Level 을 추가합니다.
"Microsoft.AspNetCore.Hosting": "Information",
"Microsoft.AspNetCore.Routing.EndpointMiddleware": "Information"
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.AspNetCore.Hosting": "Information",
"Microsoft.AspNetCore.Routing.EndpointMiddleware": "Information"
}
}
}
8. 프로젝트를 실행하여 Server 를 구동합니다.
1. 콘솔앱 프로젝트 생성
2. Server 에서 만들어진 proto 파일을 동일하게 Protos 폴더를 만들어 복사/붙여 넣기 합니다.
3. Proto 통신에 필요한 Nuget 패키지를 설치합니다.
Google.Protobuf
Grpc.Net.Client
Grpc.Tools
4. 프로젝트파일 편집
Server 를 Client 로 아래처럼 바꿉니다.
<Protobuf Include="Protos\weather.proto" GrpcServices="Client" />
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<None Remove="Protos\weather.proto" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="3.20.1" />
<PackageReference Include="Grpc.Net.Client" Version="2.45.0" />
<PackageReference Include="Grpc.Tools" Version="2.45.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Protobuf Include="Protos\weather.proto" GrpcServices="Client" />
</ItemGroup>
</Project>
4. 빌드합니다.
빌드하게 되면 proto 파일을 이용해 c# 코드가 생성됩니다. (솔루션 탐색기에서 표시되지 않음)
5. 서버 연결 및 통신 처리
using Google.Protobuf.WellKnownTypes;
using Grpc.Core;
using Grpc.Net.Client;
using GrpcStreamClient;
using var channel = GrpcChannel.ForAddress("http://localhost:5038");
var client = new WeatherForecasts.WeatherForecastsClient(channel);
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
using var streamingCall = client.GetWeatherStream(new Empty(), cancellationToken: cts.Token);
try
{
await foreach (var weatherData in streamingCall.ResponseStream.ReadAllAsync(cancellationToken: cts.Token))
{
Console.WriteLine($"{weatherData.DateTimeStamp.ToDateTime():s} | {weatherData.Summary} | {weatherData.TemperatureC} C");
}
}
catch (RpcException ex) when (ex.StatusCode == StatusCode.Cancelled)
{
Console.WriteLine("Stream cancelled.");
}
http 주소로 연결합니다.
GetWeatherStream 을 호출하면 서버에서 데이터를 실시간으로 전달해 줍니다.
CancellationTokenSource 로 5초 지나면 호출을 Cancel 합니다.
아래는 서버와 클라이언트 간 테스트 결과
소스 : https://github.com/kei-soft/GrpcSample
참고
C# gRPC Interceptor 사용하기 (0) | 2024.04.25 |
---|---|
C# gRPC Streaming 에러 HTTP/2 INTERNAL_ERROR (0) | 2024.04.25 |
C# gRPC 를 이용해 Server와 Client 통신 처리하기 (0) | 2024.04.25 |
C# Prometheus, OpenTelemetry 이용하여 매트릭 데이터 보기 (0) | 2024.04.24 |
C# Metric 데이터 수집하고 모니터링 하기 (dotnet-counters) (0) | 2024.04.24 |