.net core grpc 实现通信(一)

.net core grpc 2019-12-07 4309  

现在系统都服务化,.net core 实现服务化的方式有很多,我们通过grpc实现客户端、服务端通信。 grpc([https://grpc.io/](https://grpc.io/))是google发布的一个开源、高性能、通用RPC(Remote Procedure Call)框架,使用HTTP/2协议,支持多路复用,并用ProtoBuf作为序列化工具,提供跨语言、跨平台支持。下面以.net core演示如何使用grpc框架实现通信。 软件版本 .net core:2.0 grpc:1.11.0 #### 项目结构 #### InstallGrpc .net framework类库 只为得到生成协议代码工具protoc.exe、grpc_csharp_plugin.exe,没有其他作用,如果已有工具,可以不用 Snai.GrpcClient 客户端 .net core 2.0控制台程序 Snai.GrpcService.Hosting 服务端宿主 .net core 2.0控制台程序 Snai.GrpcService.Impl 协议方法实现 .net standard 2.0类库 Snai.GrpcService.Protocol 生成协议方法 .net standard 2.0类库 ![Image](/sitedata/image/dotnet_1_1.png) #### 运行结果 #### 服务端 ![Image](/sitedata/image/dotnet_1_2.png) 客户端 ![Image](/sitedata/image/dotnet_1_3.png) 客户端调用服务端求和方法成功。 #### 项目实现 #### **一、服务端** 新建Snai.GrpcService解决方案 1、编写协议 新建 Snai.GrpcService.Protocol协议类库项目,在 依赖项 右击 管理NuGet程序包 浏览 找到 Grpc.Core 版本1.11.0,Google.Protobuf 版本3.5.1 包下载安装 在项目根目录下新建一个 msg.proto 文件,打开 msg.proto 文件,在其中编写基于proto3语言的协议代码,用于自动生成到各语言协议,如果需要更深入的学习proto3语言可以打开该网站Proto3语言指南。msg.proto 代码如下 定义当前使用的是proto3语言并且包名(生成为C#则为命名空间): ``` syntax = "proto3"; package Snai.GrpcService.Protocol; ``` 定义了1个服务,且有1个方法: ``` service MsgService{ rpc GetSum(GetMsgNumRequest) returns (GetMsgSumReply){} } ``` 方法的接收参数和返回参数 ``` message GetMsgNumRequest { int32 Num1 = 1; int32 Num2 = 2; } message GetMsgSumReply { int32 Sum = 1; } ``` 2、将协议生成C#代码 生成协议代码需 protoc.exe、grpc_csharp_plugin.exe工具,在.net framework 项目下引用安装 Grpc.Tools 组件程序包,会得到protoc.exe、grpc_csharp_plugin.exe,但.net core 项目引用安装是不会下载工具到项目目录的,所以我们需要建一个.net framework项目,我建了个 InstallGrpc .net framework类库 用于引用安装得到工具。 这里得到工具有个小插曲,引用Grpc.Tools版本1.11.0得到protoc.exe、grpc_csharp_plugin.exe 拷到 Snai.GrpcService.Protocol 目录下生成不了,我再引用Google.Protobuf.Tools版本3.5.1里面有 protoc.exe,用 Grpc.Tools下的 grpc_csharp_plugin.exe, Google.Protobuf.Tools下protoc.exe 根据当前系统选择,拷贝到 Snai.GrpcService.Protocol 目录下。 先用Grpc.Tools 下的,如果生成不了,再用 Grpc.Tools下的 grpc_csharp_plugin.exe, Google.Protobuf.Tools下protoc.exe 然后在项目中新建一个名为ProtocGenerate.cmd的文件,在其中输入以下指令: ``` protoc -I . --csharp_out . --grpc_out . --plugin=protoc-gen-grpc=grpc_csharp_plugin.exe msg.proto ``` 然后直接双击运行,项目下生成了“Msg.cs”和“MsgGrpc.cs”两个文件,这样协议部分的所有工作就完成了,最终项目结构如下: ![Image](/sitedata/image/dotnet_1_4.png) 3、编写协议实现代码 新建Snai.GrpcService.Impl实现类库项目,在 依赖项 下载安装Grpc.Core 包,项目引用Snai.GrpcService.Protocol 在项目根目录下新建 MsgServiceImpl.cs 类文件,继承 MsgService.MsgServiceBase 协议类,实现服务方法,代码如下: ``` using Grpc.Core; using Snai.GrpcService.Protocol; using System; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; namespace Snai.GrpcService.Impl { public class MsgServiceImpl: MsgService.MsgServiceBase { public MsgServiceImpl() { } public override async Task<GetMsgSumReply> GetSum(GetMsgNumRequest request, ServerCallContext context) { var result = new GetMsgSumReply(); result.Sum = request.Num1 + request.Num2; return result; } } } ``` 在项目根目录下新建 RpcConfig.cs 类文件,编写绑定服务到服务端,服务端 地址 端口 等信息,实现启动方法,代码如下: ``` using Grpc.Core; using Snai.GrpcService.Protocol; using System; using System.Collections.Generic; using System.Text; namespace Snai.GrpcService.Impl { public static class RpcConfig { private static Server _server; public static void Start() { _server = new Server { Services = { MsgService.BindService(new MsgServiceImpl()) }, Ports = { new ServerPort("localhost", 40001, ServerCredentials.Insecure) } }; _server.Start(); Console.WriteLine("grpc ServerListening On Port 40001"); Console.WriteLine("任意键退出..."); Console.ReadKey(); _server?.ShutdownAsync().Wait(); } } } ``` 最终项目结构如下: ![Image](/sitedata/image/dotnet_1_5.png) 4、编写服务端启动程序 新建Snai.GrpcService.Hosting 控制台程序,项目引用Snai.GrpcService.Impl 打开 Program.cs 文件,修改 Main 方法,加入服务启动,代码如下: ``` using Snai.GrpcService.Impl; using System; namespace Snai.GrpcService.Hosting { class Program { static void Main(string[] args) { RpcConfig.Start(); } } } ``` 最终项目结构如下: ![Image](/sitedata/image/dotnet_1_6.png) 到此服务端所有代码已编写完成,下面开始编写客户端。 **二、客户端** 新建Snai.GrpcClient 控制台程序,在 依赖项 下载安装Grpc.Core 包,项目引用Snai.GrpcService.Protocol 在项目根目录下新建 MsgServiceClient.cs 类文件,编写与服务端通信的 地址 端口 等信息,并调用服务端方法,代码如下: ``` using Grpc.Core; using Snai.GrpcService.Protocol; using System; using System.Collections.Generic; using System.Text; namespace Snai.GrpcClient { public static class MsgServiceClient { private static Channel _channel; private static MsgService.MsgServiceClient _client; static MsgServiceClient() { _channel = new Channel("127.0.0.1:40001", ChannelCredentials.Insecure); _client = new MsgService.MsgServiceClient(_channel); } public static GetMsgSumReply GetSum(int num1, int num2) { return _client.GetSum(new GetMsgNumRequest { Num1 = num1, Num2 = num2 }); } } } ``` 打开 Program.cs 文件,修改 Main 方法,得到服务端返回结果,显示结果,代码如下: ``` using Snai.GrpcService.Protocol; using System; namespace Snai.GrpcClient { class Program { static void Main(string[] args) { GetMsgSumReply msgSum = MsgServiceClient.GetSum(10, 2); Console.WriteLine("grpc Client Call GetSum():" + msgSum.Sum); Console.WriteLine("任意键退出..."); Console.ReadKey(); } } } ``` 最终项目结构如下: ![Image](/sitedata/image/dotnet_1_7.png) 到此所有代码都已编写完成。 **三、启动** 右击生成解决方案,生成完成后,先启动服务端,再启动客户端 命令行到服务端目录 Snai.GrpcService.Hosting\bin\Debug\netcoreapp2.0\,用命令 dotnet Snai.GrpcService.Hosting.dll 启动服务端 ![Image](/sitedata/image/dotnet_1_8.png) 命令行到客户端目录 Snai.GrpcClient\bin\Debug\netcoreapp2.0\,用命令 dotnet Snai.GrpcClient.dll 启动客户端 ![Image](/sitedata/image/dotnet_1_9.png) 客户端调用服务端方法成功,实现grpc 它们之间是通过Grpc.Core中的 Server 和 Channel 来通信 Github源码地址:[https://github.com/Liu-Alan/Snai.GrpcService](https://github.com/Liu-Alan/Snai.GrpcService)