#.NET 客戶端調用 gRPC 服務的四種通信方式
- 一元調用
- 客戶端流模式
- 雙向流模式
- 服務端流模式
一元調用
一元調用從客戶端發送請求消息開始。 服務完成後,將返回響應消息。
客戶端流模式
客戶端流式處理調用在客戶端發送消息的情況下啓動。 客戶端可以選擇發送發送消息RequestStream.WriteAsync。 當客戶端已經完成發送消息RequestStream.CompleteAsync時,應調用來通知服務。 當服務返回響應消息時,調用完成。
雙向流模式
雙向流式處理調用在客戶端發送消息的情況下啓動。 客戶端可以選擇通過RequestStream.WriteAsync發送消息。 可以通過或ResponseStream.ReadAllAsync()訪問從服務流式處理ResponseStream.MoveNext()的消息。 當沒有更多消息時ResponseStream ,雙向流式處理調用完成。
服務端流模式
服務器流式處理調用會從客戶端發送請求消息開始。 ResponseStream.MoveNext()讀取從服務傳輸的消息。 ResponseStream.MoveNext() 返回false時,服務器流調用已完成。
代碼 Protos
syntax = "proto3";
option csharp_namespace = "GrpcService1";
import "google/protobuf/empty.proto";
package Count;
service Counter{
rpc AddStream(stream NumberRequest) returns (ResultReply);
rpc Add(TwoNumberRequest) returns (ResultReply);
rpc AddTwoStream(stream NumberRequest) returns (stream ResultReply);
rpc GetInfo(google.protobuf.Empty) returns (ResultReply);
}
message TwoNumberRequest{
int32 num1=1;
int32 num2=2;
}
message NumberRequest{
int32 num=1;
}
message ResultReply{
int32 num=1;
}
代碼 服務端
public class CountService : Counter.CounterBase
{
private readonly ILogger<CountService> _logger;
public CountService(ILogger<CountService> logger)
{
_logger = logger;
}
//一元請求
public override Task<ResultReply> Add(TwoNumberRequest request, ServerCallContext context)
{
return Task.FromResult(new ResultReply() { Num = request.Num1 + request.Num2 });
}
/// <summary>
/// 雙向流請求
/// </summary>
/// <param name="requestStream"></param>
/// <param name="responseStream"></param>
/// <param name="context"></param>
/// <returns></returns>
public override async Task AddTwoStream(IAsyncStreamReader<NumberRequest> requestStream, IServerStreamWriter<ResultReply> responseStream, ServerCallContext context)
{
int result = 0;
while (await requestStream.MoveNext())
{
result += requestStream.Current.Num;
await responseStream.WriteAsync(new ResultReply() { Num = result });
await Task.Delay(1000);
}
await responseStream.WriteAsync(new ResultReply() { Num = result*1000 });
}
/// <summary>
/// 客戶端流程求
/// </summary>
/// <param name="requestStream"></param>
/// <param name="context"></param>
/// <returns></returns>
public override async Task<ResultReply> AddStream(IAsyncStreamReader<NumberRequest> requestStream, ServerCallContext context)
{
int result = 0;
while (await requestStream.MoveNext())
{
result += requestStream.Current.Num;
}
return await Task.FromResult(new ResultReply() { Num = result });
}
public override Task<ResultReply> GetInfo(Empty request, ServerCallContext context)
{
return base.GetInfo(request, context);
}
}
代碼 客戶端
class Program
{
static async System.Threading.Tasks.Task Main(string[] args)
{
Console.WriteLine("Hello World!");
var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new GrpcService1.Counter.CounterClient(channel);
Console.WriteLine("一元請求");
var result = client.Add(new GrpcService1.TwoNumberRequest() { Num1 = 1, Num2 = 1 });
Console.WriteLine($"一元請求結果{result.Num}");
Console.WriteLine("-----------------------");
Console.WriteLine("客戶端流請求");
var clientStream = client.AddStream();
for (var i = 0; i < 10; i++)
{
await clientStream.RequestStream.WriteAsync(new GrpcService1.NumberRequest() { Num = i });
}
clientStream.RequestStream.CompleteAsync();
var resut1 = await clientStream;
Console.WriteLine($"客戶端流請求結果{resut1.Num}");
Console.WriteLine("-----------------------");
Console.WriteLine("雙向流");
var doubleStream = client.AddTwoStream();
Task.Run(async () =>
{
await foreach (var resp in doubleStream.ResponseStream.ReadAllAsync())
{
Console.WriteLine($"中間結果:{resp.Num}");
}
});
for (var i = 0; i < 10; i++)
{
await doubleStream.RequestStream.WriteAsync(new GrpcService1.NumberRequest() { Num = i });
}
doubleStream.RequestStream.CompleteAsync();
Console.ReadLine();
}
}
完