gRPC 是一种高性能、开源的远程过程调用(RPC)框架,支持多种编程语言。本文将介绍如何在 C# 中使用 gRPC 进行通讯,包括创建 gRPC 服务文件、封装服务端和客户端类库,以及进行简单的测试。
参考 : C#封装GRPC类库及调用简单实例 - wtc87 - 博客园 (cnblogs.com)
创建并生成 gRPC 服务文件
-
首先,创建一个新的控制台应用程序项目,命名为
MgRPC
。 -
在项目中安装以下 NuGet 包:
Google.Protobuf
Grpc.Core
Grpc.Tools
定义 Protocol Buffer 文件
在项目中添加一个新的类文件,命名为 Link.proto
,并清空其内容。然后添加以下代码:
csharp
syntax = "proto3";
// 指定了生成的 C# 代码的命名空间为 LinkService。当使用 protobuf 编译器 (protoc) 将这个 .proto 文件转换为 C# 代码时,生成的类将位于 LinkService 命名空间中
option csharp_namespace = "LinkService";
//定义了一个名为 Link 的 gRPC 服务。在 gRPC 中,服务是由一个或多个 RPC 方法组成的
service Link
{
//定义了一个 RPC 方法。这个方法名为 GetMessage,它接受一个 Mes 类型的消息作为参数,
//并返回一个 Mes 类型的消息。在 gRPC 中,客户端可以调用这个方法,并发送一个 Mes 消息给服务端,然后服务端会处理这个消息并返回一个 Mes 消息给客户端。
rpc GetMessage(Mes) returns (Mes);
}
//定义了一个名为 Mes 的消息类型。在 protobuf 中,消息是由一系列字段组成的,每个字段都有一个名称、一个类型和一个标识符。
message Mes
{
// 客户端发送
// 定义了一个名为 StrRequest 的字段,类型为 string,标识符为 1。这个标识符在消息内部是唯一的,并且一旦分配就不能更改,因为它被用于序列化和反序列化过程中的字段识别。
string StrRequest = 1;
// 同样定义了一个名为 StrReply 的字段,类型为 string,标识符为 2。(服务端回复)
string StrReply = 2;
}
设置 Link.proto 文件属性
右键点击 Link.proto
文件,选择属性,将"生成操作"设置为 Protobuf compiler
。
生成 C# 代码
生成解决方案后,会在项目目录下生成 Link.cs
和 LinkGrpc.cs
两个文件。
服务端和客户端类库的封装
- 创建一个新的类库项目,命名为
GrpcLink
。 - 项目添加现有项,将生成的
Link.cs
和LinkGrpc.cs
文件添加到项目中,并安装Grpc.Core
和Google.Protobuf
NuGet 包。 - 创建两个类:LinkFunc用于放此类库可用于外部引用调用的方法。LinkServerFunc基于Link.LinkBase,用于重写在proto文件中定义的方法。
对于不同的项目,在客户端请求时,服务端要根据自身情况回复想回的内容,因此可以提供一个委托供外部自行开发回复函数。
在LinkFunc类中定义如下:
csharp
public static Func<string, string> ReplyMes;
创建服务端和客户端类
在项目中创建两个类:LinkFunc
和 LinkServerFunc
。
LinkServerFunc 类
csharp
using Grpc.Core;
using LinkService;
using System.Threading.Tasks;
using static LinkService.Link;
namespace GrpcLink
{
/// <summary>
/// 重写在proto文件中定义的方法
/// </summary>
public class LinkServerFunc : LinkBase
{
public override Task<Mes> GetMessage(Mes request,ServerCallContext context)
{
Mes mes = new Mes();
mes.StrReply = LinkFunc.ReplyMes(request.StrRequest);
return Task.FromResult(mes);
}
}
}
LinkFunc 类
csharp
using Grpc.Core;
using LinkService;
using System;
using static LinkService.Link;
namespace GrpcLink
{
public class LinkFunc
{
/// <summary>
/// 用于服务端回复委托
/// </summary>
public static Func<string,string> ReplyMes;
// 定义服务端和客户端
public static Server LinkServer;
public static LinkClient LinkClient;
/// <summary>
/// 服务端启动
/// </summary>
/// <param name="host"></param>
/// <param name="port"></param>
public static void LinkServerStart(string host,int port)
{
LinkServer = new Server
{
Services =
{
BindService(new LinkServerFunc())
},
Ports = { new ServerPort(host,port,ServerCredentials.Insecure) }
};
LinkServer.Start();
}
/// <summary>
/// 服务端关闭
/// </summary>
public static void LinkServerClose()
{
LinkServer?.ShutdownAsync().Wait();
}
/// <summary>
/// 客户端启动
/// </summary>
/// <param name="strIp"></param>
public static void LinkClientStart(string strIp)
{
Channel prechannel = new Channel(strIp,ChannelCredentials.Insecure);
LinkClient = new LinkClient(prechannel);
}
/// <summary>
/// 客户端发送消息函数
/// </summary>
/// <param name="strRequest"></param>
/// <returns></returns>
public static string SendMes(string strRequest)
{
Mes mes = new Mes();
mes.StrRequest = strRequest;
var res = LinkClient.GetMessage(mes);
return res.StrReply;
}
}
}
生成引用库
生成解决方案后,会在 Debug
目录下生成 GrpcLink.dll
文件,其他项目可以引用该文件。
创建服务端和客户端调用测试
- 创建两个控制台应用程序项目,分别命名为
TestServer
和TestClient
。 - 将
GrpcLink.dll
文件分别添加到两个项目中,并添加引用。
TestServer 服务端
csharp
using GrpcLink;
using System;
using System.Threading;
namespace TestServer
{
/// <summary>
/// 测试服务端
/// </summary>
internal class Program
{
static void Main(string[] args)
{
LinkFunc.LinkServerStart("127.0.0.1",9008);
Thread.Sleep(500);
LinkFunc.ReplyMes = ReplyMes;
Console.ReadKey();
}
/// <summary>
/// 接收到客户端信息后回复
/// </summary>
/// <param name="strRequest">客户端发送过来的内容</param>
/// <returns></returns>
public static string ReplyMes(string strRequest)
{
Console.WriteLine("接收到:" + strRequest);
switch (strRequest)
{
case "1":
return "Server识别到1";
case "2":
return "Server识别到2";
case "测试":
return "开始测试";
case "连接服务端":
return "true";
}
return "Server未识别到指定参数";
}
}
}
TestCilent 客户端
csharp
using GrpcLink;
using System;
using System.Threading;
namespace TestCilent
{
internal class Program
{
static void Main(string[] args)
{
Thread.Sleep(2000);
LinkFunc.LinkClientStart("127.0.0.1:9008");
Console.WriteLine("连接服务端中");
string conn = LinkFunc.SendMes("连接服务端");
if (conn.Equals("true"))
{
Console.WriteLine("连接服务端成功!");
for (int i = 0 ; i < 10 ; i++)
{
Thread.Sleep(1000);
Console.WriteLine("输入测试内容..");
var line = Console.ReadLine();
var ret = LinkFunc.SendMes(line);
//获取到服务端返回的值
Console.WriteLine(ret);
}
}
Console.WriteLine("连接失败 , 即将退出");
Thread.Sleep(2000);
}
}
}
测试图例