<三>GRPC双向流

直接使用晓晨Master大佬的给猫洗澡的例子。原文链接:ASP.NET Core 3.0 gRPC 双向流

1、定义 SayHi.ptoto文件添加两个方法,一个计算猫数量,一个给猫洗澡。client端和服务端都要

syntax = "proto3";

option csharp_namespace = "GrpcClient";
import "google/protobuf/empty.proto";
package SayHi;


//定义服务
service SayHier{
    //定义
    rpc SayHillo(SayHiRequest) returns(SayHiResult);
    rpc BathTheCat(stream BathTheCatReq) returns ( stream BathTheCatResp);
    rpc Count(google.protobuf.Empty) returns (CountCatResult);
}

message SayHiRequest
{
    string name=1;
}


message SayHiResult{
    string message=1;
}
message BathTheCatReq{
    int32 id=1;
}
message BathTheCatResp{
    string message=1;
}
message CountCatResult{
    int32 Count=1;
}

2、实现服务

public class SayHierService : SayHier.SayHierBase
    {
        private static readonly List<string> Cats = new List<string>() { "英短银渐层", "英短金渐层", "美短", "蓝猫", "狸花猫", "橘猫" };
        private static readonly Random Rand = new Random(DateTime.Now.Millisecond);
        public override Task<SayHiResult> SayHillo(SayHiRequest  request, ServerCallContext context)
        {
            return Task.FromResult(new SayHiResult
            {
                Message = "Hillo " + request.Name
            });
        }

        public override async Task BathTheCat(IAsyncStreamReader<BathTheCatReq> requestStream, IServerStreamWriter<BathTheCatResp> responseStream, ServerCallContext context)
        {
            var bathQueue = new Queue<int>();
            while (await requestStream.MoveNext())
            {
                //将要洗澡的猫加入队列
                bathQueue.Enqueue(requestStream.Current.Id);

               // _logger.LogInformation($"Cat {requestStream.Current.Id} Enqueue.");
            }

            //遍历队列开始洗澡
            while (bathQueue.TryDequeue(out var catId))
            {
                await responseStream.WriteAsync(new BathTheCatResp() { Message = $"铲屎的成功给一只{Cats[catId]}洗了澡!" });

                await Task.Delay(500);//此处主要是为了方便客户端能看出流调用的效果
            }
        }

        public override Task<CountCatResult> Count(Empty request, ServerCallContext context)
        {
            return Task.FromResult(new CountCatResult()
            {
                Count = Cats.Count
            });
        }

    }

3、实现客户端调用服务

   var channel = GrpcChannel.ForAddress("https://localhost:5001");
            var catClient = new SayHier.SayHierClient(channel);
            //获取猫总数
            var catCount = await catClient.CountAsync(new Empty());
            Console.WriteLine($"一共{catCount.Count}只猫。");
            var rand = new Random(DateTime.Now.Millisecond);
        
            var bathCat = catClient.BathTheCat();
            //定义接收吸猫响应逻辑
            var bathCatRespTask = Task.Run(async () =>
           {
             
                   while (await bathCat.ResponseStream.MoveNext(CancellationToken.None))
                   {
                       Console.WriteLine(bathCat.ResponseStream.Current.Message);
                   }
            
           });
            //随机给10个猫洗澡
            for (int i = 0; i < 10; i++)
            {
                await bathCat.RequestStream.WriteAsync(new BathTheCatReq() { Id = rand.Next(0, catCount.Count) });
            }
            //发送完毕
            await bathCat.RequestStream.CompleteAsync();
            Console.WriteLine("客户端已发送完10个需要洗澡的猫id");
            Console.WriteLine("接收洗澡结果:");
            //开始接收响应
            await bathCatRespTask;

            Console.WriteLine("洗澡完毕");

 

4、运行

 

 

5、限流,在客户端接收MoveNext函数里传一个CancellationToken,具体代码如下:

 

   var channel = GrpcChannel.ForAddress("https://localhost:5001");
            var catClient = new SayHier.SayHierClient(channel);
            //获取猫总数
            var catCount = await catClient.CountAsync(new Empty());
            Console.WriteLine($"一共{catCount.Count}只猫。");
            var rand = new Random(DateTime.Now.Millisecond);
            var cts = new CancellationTokenSource();
            //指定在2.5s后进行取消操作
            cts.CancelAfter(TimeSpan.FromSeconds(2.5));
            var bathCat = catClient.BathTheCat();
            //定义接收吸猫响应逻辑
            var bathCatRespTask = Task.Run(async () =>
           {
               try
               {
                   while (await bathCat.ResponseStream.MoveNext(cts.Token))
                   {
                       Console.WriteLine(bathCat.ResponseStream.Current.Message);
                   }
               }
               catch (RpcException ex) when (ex.StatusCode == StatusCode.Cancelled)
               {
                   Console.WriteLine("Stream cancelled.");
               }

           });
            //随机给10个猫洗澡
            for (int i = 0; i < 10; i++)
            {
                await bathCat.RequestStream.WriteAsync(new BathTheCatReq() { Id = rand.Next(0, catCount.Count) });
            }
            //发送完毕
            await bathCat.RequestStream.CompleteAsync();
            Console.WriteLine("客户端已发送完10个需要洗澡的猫id");
            Console.WriteLine("接收洗澡结果:");
            //开始接收响应
            await bathCatRespTask;

            Console.WriteLine("洗澡完毕");

 

6、运行结果

 

posted @ 2020-05-09 17:13  许轩霖  阅读(117)  评论(0编辑  收藏  举报