#.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();
}
}
完