欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

GRPC与.net core

程序员文章站 2022-06-09 14:15:55
系列章节 GRPC与.net core GRPC截止时间与元数据 GRPC与netcore Identity GRPC与netcore IdentityServer4 概述 GRPC的数据交互模式有: 1.单项RPC,最简单的数据交换方式,客户端发出单个请求,收到单个响应 2.服务端流式RPC,是在 ......

系列章节

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包

GRPC与.net core

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="protos\greet.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();
        }
    }
}

 

文件生成成功

GRPC与.net core

 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的几种数据交互分享完毕