• GRPC与.net core


    系列章节

    GRPC与.net core

    GRPC截止时间与元数据

    GRPC与netcore Identity

    GRPC与netcore IdentityServer4

    概述

    GRPC的数据交互模式有:

    1.单项RPC,最简单的数据交换方式,客户端发出单个请求,收到单个响应

    2.服务端流式RPC,是在服务端收到客户端的请求之后,返回一个应答流,客户端收到流之后处理。

    3.客户端流式RPC,与单项类似,但客户端发送的是流式RPC

    4.双向流式RPC,调用由客户端调用方法来初始化,而服务端则接收到客户端的元数据,方法名和截止时间。服务端可以选择发送回它的初始元数据或等待客户端发送请求。下一步怎样发展取决于应用,因为客户端和服务端能在任意顺序上读写 - 这些流的操作是完全独立的。例如服务端可以一直等直到它接收到所有客户端的消息才写应答,或者服务端和客户端可以像"乒乓球"一样:服务端后得到一个请求就回送一个应答,接着客户端根据应答来发送另一个请求,以此类推。

    单项RPC较简单不做示例了。

    首先在vs2019中net core3.0中新建GRPC项目。然后定义响应的proto文件,根据proto文件生成响应的服务端与客户端代码。

    1.服务端流式RPC

    1.定义 protofile

    syntax = "proto3";
    
    option csharp_namespace = "GrpcGreeter";
    
    package Greet;
    
    // The greeting service definition.
    service Greeter {
      // Sends a greeting
      rpc SayHello (HelloRequest) returns (HelloReply) {}
      rpc GetStreamContent (StreamRequest) returns (stream StreamContent) {}
    }
    
    // The request message containing the user's name.
    message HelloRequest {
      string name = 1;
    }
    
    // The response message containing the greetings.
    message HelloReply {
      string message = 1;
    }
    message StreamRequest {
      string fileName = 1;
    }
    message StreamContent {
      bytes content = 1;
    }

    2.实现服务端Service

    重新生成项目,然后实现GetStreamContent,简单的读取文件内容,并将内容返回给Client

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Threading.Tasks;
    using Google.Protobuf;
    using Grpc.Core;
    
    namespace GrpcGreeter
    {
        public class GreeterService : Greeter.GreeterBase
        {
            public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
            {
                return Task.FromResult(new HelloReply
                {
                    Message = "Hello " + request.Name
                });
            }
    
            public override Task GetStreamContent(StreamRequest request, IServerStreamWriter<StreamContent> responseStream, ServerCallContext context)
            {
                return Task.Run(async () =>
                 {
                     using (var fs = File.Open(request.FileName, FileMode.Open)) // 从 request 中读取文件名并打开文件流
                     {
                         var remainingLength = fs.Length; // 剩余长度
                         var buff = new byte[1048576]; // 缓冲区,这里我们设置为 1 Mb
                         while (remainingLength > 0) // 若未读完则继续读取
                         {
                             var len = await fs.ReadAsync(buff); // 异步从文件中读取数据到缓冲区中
                             remainingLength -= len; // 剩余长度减去刚才实际读取的长度
    
                             // 向流中写入我们刚刚读取的数据
                             await responseStream.WriteAsync(new StreamContent
                             {
                                 Content = ByteString.CopyFrom(buff, 0, len)
                             });
                         }
                     }
                 });
            }
        }
    }

    3.实现Client

    新建一个netcore 3.0的Console项目,并引入Nuget包

    Install-Package Grpc.Net.Client -Version 0.1.22-pre1
    Install-Package Google.Protobuf -Version 3.8.0
    Install-Package Grpc.Tools -Version 1.22.0

    编辑项目文件,修改如下节点

    <Protobuf Include="Protosgreet.proto" GrpcServices="Client" />

    重新生成项目,Client端主要实现发送请求,请求是一个服务器端的文件路径。然后实现接收服务端的流,并保存到Client本地。

    using Grpc.Net.Client;
    using GrpcGreeter;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net.Http;
    
    namespace GrpcGreeterClient
    {
        class Program
        {
            static async System.Threading.Tasks.Task Main(string[] args)
            {
                AppContext.SetSwitch(
                    "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport",
                    true);
                var httpClient = new HttpClient();
                // The port number(50051) must match the port of the gRPC server.
                httpClient.BaseAddress = new Uri("http://localhost:50051");
                var client = GrpcClient.Create<Greeter.GreeterClient>(httpClient);
                //
                var reply = await client.SayHelloAsync(
                                  new HelloRequest { Name = "GreeterClient" });
                Console.WriteLine("Greeting: " + reply.Message);
                Console.ReadKey();
    
                //
                var result = client.GetStreamContent(new StreamRequest { FileName = @"D:Docs.zip" });  //发送请求
                var iter = result.ResponseStream;
                using (var fs = new FileStream(@"D:Docs2.zip", FileMode.Create)) // 新建一个文件流用于存放我们获取到数据
                {
                    while (await iter.MoveNext()) // 迭代
                    {
                        iter.Current.Content.WriteTo(fs); // 将数据写入到文件流中
                    }
                }
    
                Console.ReadKey();
            }
        }
    }

    文件生成成功

     2.客户端流式RPC

    1.定义 protofile

    syntax = "proto3";
    
    option csharp_namespace = "GRPC.TEST";
    
    package Greet;
    
    // The greeting service definition.
    service Greeter {
      rpc getResult (stream Value) returns (Result) {}
    }
    
    
    //定义Value消息类型,用于客户端消息
    message Value {
        int32 value = 1;
    }
    //定义Result消息类型,包含总和,数字数量和平均值,用于服务端消息返回
    message Result {
        int32 sum = 1;
        int32 cnt = 2;
        double avg = 3;
    }

    2.实现服务端Service

    重新生成项目,并实现如下

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Threading.Tasks;
    using Google.Protobuf;
    using Grpc.Core;
    
    namespace GRPC.TEST
    {
        public class GreeterService : Greeter.GreeterBase
        {
            public override async Task<Result> getResult(IAsyncStreamReader<Value> requestStream, ServerCallContext context)
            {
                while (await requestStream.MoveNext())
                {
                    var point = requestStream.Current;
                }
                return new Result { Sum = 1 };
            }
        }
    }

    3.实现Client

    新建一个netcore 3.0的Console项目,并引入Nuget包,安装nuget包与其他操作同上一个例子,实现代码如下

    using Grpc.Net.Client;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net.Http;
    
    namespace GRPC.TEST.CLIENT
    {
        class Program
        {
            static async System.Threading.Tasks.Task Main(string[] args)
            {
                AppContext.SetSwitch(
                     "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport",
                     true);
                var httpClient = new HttpClient();
                // The port number(50051) must match the port of the gRPC server.
                httpClient.BaseAddress = new Uri("http://localhost:50051");
                var client = GrpcClient.Create<Greeter.GreeterClient>(httpClient);
                using (var call = client.getResult())
                {
                    await call.RequestStream.WriteAsync(new Value { Value_ = 1 });
                    await call.RequestStream.CompleteAsync();
                    var response = await call.ResponseAsync;
                }
    
                Console.ReadKey();
            }
        }
    }

     3.双向流式RPC

    1.定义proto

    syntax = "proto3";
    
    option csharp_namespace = "GRPC.TEST";
    
    package Greet;
    
    // The greeting service definition.
    service Greeter {
      rpc getResult (stream Value) returns (stream Result) {}
    }
    
    
    //定义Value消息类型,用于客户端消息
    message Value {
        int32 value = 1;
    }
    //定义Result消息类型,包含总和,数字数量和平均值,用于服务端消息返回
    message Result {
        int32 sum = 1;
        int32 cnt = 2;
        double avg = 3;
    }

    2.服务端实现

    重新生成项目,并实现如下

    public override async Task getResult(IAsyncStreamReader<Value> requestStream, IServerStreamWriter<Result> responseStream, ServerCallContext context)
            {
                while (await requestStream.MoveNext())
                {
                    var note = requestStream.Current;
    
                    await responseStream.WriteAsync(new Result { Sum = 100 });
                }
            }

    3.客户端代码

    新建一个netcore 3.0的Console项目,并引入Nuget包,安装nuget包与其他操作同上一个例子,实现代码如下

    using Grpc.Net.Client;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net.Http;
    using System.Threading.Tasks;
    
    namespace GRPC.TEST.CLIENT
    {
        class Program
        {
            static async System.Threading.Tasks.Task Main(string[] args)
            {
                AppContext.SetSwitch(
           "System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport",
           true);
                var httpClient = new HttpClient();
                // The port number(50051) must match the port of the gRPC server.
                httpClient.BaseAddress = new Uri("http://localhost:50051");
                var client = GrpcClient.Create<Greeter.GreeterClient>(httpClient);
                using (var call = client.getResult())
                {
                    var responseReaderTask = Task.Run(async () =>
                    {
                        while (await call.ResponseStream.MoveNext())
                        {
                            var note = call.ResponseStream.Current;
                            Console.WriteLine("Received " + note);
                        }
                    });
    
                    await call.RequestStream.WriteAsync(new Value { Value_ = 12 });
                    await call.RequestStream.CompleteAsync();
                    await responseReaderTask;
                }
    
                Console.ReadKey();
            }
        }
    }

    至此,GRPC的几种数据交互分享完毕

  • 相关阅读:
    面向对象(metaclass继承高级用法)
    建表和删表(sqlalchemy框架)
    单表操作
    认证,权限
    协程,twisted
    定制起始url(scrapy_redis)
    浅谈深度优先和广度优先(scrapy-redis)
    scrapy-redis(调度器Scheduler源码分析)
    scrapy-redis
    xpath
  • 原文地址:https://www.cnblogs.com/chenyishi/p/11143375.html
Copyright © 2020-2023  润新知