gRPC是Google开源的一个现代化、高性能的RPC框架,基于HTTP/2
标准设计,同时提供多个语言版本,并支持跨语言调用,可以在任何环境中运行。
创建项目#
新建解决方案,包含3个项目
分别给3个项目安装Nuget程序包Grpc
并安装所需依赖,然后为gRpcSample
项目安装Grpc.Tools
和Google.ProtoBuf
程序包。
同时,使项目server
和client
引用项目gRpcSample
。
定义服务接口#
在gRpcSample项目的文件夹下新建Sample.proto文件,以文本方式打开,修改其中接口定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| syntax = "proto3";
option csharp_namespace = "kira.Interface";
package sampleservice;
service SampleService {
rpc ServerVersion(VersionRequest) returns (VersionResponse) {}
rpc SayHello(HelloRequest) returns (stream HelloResponse) {}
}
message VersionRequest {}
message VersionResponse {
string name = 1;
string version = 2;
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string message = 1;
}
|
这里指定了生成的类的命名空间,同时定义了两个服务函数,似乎每个函数都必须有参数(请求)和返回(响应),这一点不太清楚。具体的语法有条件的可以参考proto3 language guide。
生成服务接口#
在进行下面操作前,建议先将Grpc.Tools
拷贝到解决方案目录下,不然的话下面的命令会很长很长…
具体操作是将解决方案下packages\Grpc.Tools.2.23.0-pre1\tools\windows_x64\
里面的protoc.exe
和grpc_csharp_plugin.exe
拷贝到解决方案目录下,完成后就可以进行下一步。
在解决方案目录下打开命令窗口,并执行下面命令
Tip: 直接进入到相应文件夹下,按住Shift
键,在空白出单击鼠标右键,就可以看到菜单中多出了一项在此处打开命令窗口(W)
1
| $ protoc -IgRpcSample --csharp_out gRpcSample gRpcSample\Sample.proto --grpc_out gRpcSample --plugin=protoc-gen-grpc=grpc_csharp_plugin.exe
|
执行完没有错误的话,就可以看到gRpcSample
项目下多出了两个文件Sample.cs
和SampleGrpc.cs
,将这两个文件添加到项目gRpcSample
。
编译gRpcSample
通过。
进行到这里,基本的工作就都完成了,剩下的就是编写服务端和客户端程序了。
服务端程序#
service
项目新建类MySampleService
,并继承SampleService.SampleServiceBase
,重写刚刚定义的两个服务接口函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| namespace server
{
using System.Threading.Tasks;
using Grpc.Core;
using kira.Interface;
public class MySampleService : SampleService.SampleServiceBase
{
public override Task<VersionResponse> ServerVersion(VersionRequest request, ServerCallContext context)
{
return Task.FromResult<VersionResponse>(
new VersionResponse()
{
Name = "My Sample Service",
Version = "0.0.1.19"
});
}
public override async Task SayHello(HelloRequest request, IServerStreamWriter<HelloResponse> responseStream, ServerCallContext context)
{
string[] hellos = { "你好", "Hello", "Hola", "Bonjour", "こんにちは", "hallo" };
foreach (string item in hellos)
{
await responseStream.WriteAsync(new HelloResponse() { Message = $"{item} {request.Name}" });
}
}
}
}
|
编写服务启动程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| namespace server
{
using Grpc.Core;
using kira.Interface;
class Program
{
static void Main(string[] args)
{
Server myServer = new Server()
{
Services = { SampleService.BindService(new MySampleService()) },
Ports = { new ServerPort("localhost", 10240, ServerCredentials.Insecure) }
};
myServer.Start();
System.Console.WriteLine("Sample Server listening on localhost:10240 \nPress any key exit...");
System.Console.ReadKey();
myServer.ShutdownAsync().Wait();
}
}
}
|
客户端程序#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| namespace client
{
using System.Threading.Tasks;
using Grpc.Core;
using kira.Interface;
class Program
{
static void Main(string[] args)
{
Program program = new Program();
program.TestService();
System.Console.ReadKey();
}
async void TestService()
{
Channel channel = new Channel("localhost:10240", ChannelCredentials.Insecure);
SampleService.SampleServiceClient cli = new SampleService.SampleServiceClient(channel);
VersionResponse ver = cli.ServerVersion(new VersionRequest());
System.Console.WriteLine("Remote Service Version: {0} - v{1}", ver.Name, ver.Version);
AsyncServerStreamingCall<HelloResponse> greetings = cli.SayHello(new HelloRequest() { Name = "gRPC" });
IAsyncStreamReader<HelloResponse> stream = greetings.ResponseStream;
while (await stream.MoveNext())
{
System.Console.WriteLine(stream.Current.Message);
}
}
}
}
|
运行测试#
首先启动服务端程序,然后运行客户端程序,可以看到客户端输出
Remote Service Version: My Sample Service - v0.0.1.19
你好 gRPC
Hello gRPC
Hola gRPC
Bonjour gRPC
こんにちは gRPC
hallo gRPC
OK,大功告成!