一. gRPC通讯简介
1.gRPC是一种高性能、开源和通用的RPC(远程过程调用)框架,由Google主导开发。gRPC基于HTTP/2协议传输,采用Protocol Buffers(protobuf)作为接口描述语言。它专为在微服务架构下进行服务器与服务器之间的通信而设计,支持各种编程语言,包括C#, Java, Python, Go等。
2.gRPC是基于HTTP/2协议传输,也属于常规的7层通讯协议,所以对于数据的传输效率并没有很大的提升。而采用Protocol Buffers进行序列化和反序列化提升了数据的序列化和反序列化性能。
二. 优缺点
gRPC通信协议具有一系列显著的优点,但也伴随着某些局限性和缺点。下面概述了gRPC的主要优缺点:
优点:
-
性能高效: 基于HTTP/2支持长连接、多路复用、服务器推送等,减少延迟,提高吞吐量。二进制传输比传统的文本协议(如HTTP/1.1)更高效。
-
跨语言支持: 具有宽泛的语言支持,可以容易地在不同的编程语言之间进行通信。
-
强类型契约: 使用Protocol Buffers强类型系统定义服务接口和消息,一旦定义完成并通过编译,编译器就可以对类型错误进行检查,从而减少运行时错误。
-
多种通信模式: 支持多种RPC模式,包括简单的请求-响应模式、服务器流式、客户端流式和双向流式。
-
集成认证、跟踪、健康检查等: 支持拦截器和中间件,使得集成第三方功能和库变得非常容易。
-
清晰的API契约: 通过
.proto
文件定义,可以清晰地理解服务的结构,也方便自动生成代码和文档。 -
简化数据序列化: Protocol Buffers是一个高效的结构化数据表示格式,可以简化数据的序列化和反序列化过程。
缺点:
-
浏览器支持有限: 因为gRPC基于HTTP/2,而且通信使用的是自定义的二进制协议,所以不同于可以直接用HTTP请求实现的RESTful APIs,gRPC在浏览器中不是那么容易接入和使用,虽然有gRPC-Web解决方案,但存在一些限制,如需要特定的代理支持。
-
生态系统: 虽然支持许多语言,但是部分语言的生态系统(如工具链和第三方库支持)可能没有RESTful APIs那么成熟。
-
普遍认知和理解程度: 相比于REST,对于新接触的开发者来说,gRPC和Protocol Buffers可能存在更陡峭的学习曲线。
-
防火墙与代理限制: 一些企业级环境的防火墙和代理可能默认不支持HTTP/2,从而需要额外的配置工作。
-
调试与跟踪: 由于gRPC使用二进制协议,导致网络调试和跟踪比基于文本的协议更为复杂。
-
版本兼容性管理: 管理.proto文件的版本兼容性需要严格的约定,否则可能由于服务定义的变更导致客户端和服务器端不匹配的问题。
-
运维复杂度:gRPC可能需要额外的配置和运维工作,比如设置负载均衡器支持HTTP/2。
三. 创建一个服务端
1.打开Vs 新建一个gRPC服务程序,创建完成之后会有一个简单的SayHello接口创建示例。
2.在.proto文件中添加参数返回值和接口名称。添加之后会自动生成对应的参数返回值接口代码
syntax = "proto3";
option csharp_namespace = "WdlGrpcServer";
package greet;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply);
// New method...
rpc SayGoodbye (GoodbyeRequest) returns (GoodbyeReply);
}
// The new request message
message GoodbyeRequest {
string name = 1;
}
// The new response message
message GoodbyeReply {
string message = 1;
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings.
message HelloReply {
string message = 1;
}
3. 在 GreeterService类中override重写刚刚在proto文件中定义的接口函数
using Grpc.Core;
using WdlGrpcServer;
namespace WdlGrpcServer.Services
{
public class GreeterService : Greeter.GreeterBase
{
private readonly ILogger<GreeterService> _logger;
public GreeterService(ILogger<GreeterService> logger)
{
_logger = logger;
}
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
return Task.FromResult(new HelloReply
{
Message = "Hello " + request.Name
});
}
public override Task<GoodbyeReply> SayGoodbye(GoodbyeRequest request, ServerCallContext context)
{
return Task.FromResult(new GoodbyeReply
{
Message = "Goodbye " + request.Name
});
}
}
}
4.确保主程序正确的加载.proto文件Server
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>
四. 创建一个客户端
1. 任意创建一个客户端程序。
2. 添加nuget包
- Grpc.Net.Client
- Google.Protobuf
- Grpc.Tools
3.将服务上定义的.proto文件拷贝到客户端
4.确保程序正确的加载.proto文件Client
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
</ItemGroup>
5. 添加客户端访问接口代码
using Grpc.Net.Client;
namespace WdlGrpcCLient
{
internal class Program
{
static async Task Main(string[] args)
{
using var channel = GrpcChannel.ForAddress("https://localhost:7248");
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(new HelloRequest { Name = "World" });
Console.WriteLine("Greeting: " + reply.Message);
// Assuming you added a SayGoodbye method as well...
var goodbyeReply = await client.SayGoodbyeAsync(new GoodbyeRequest { Name = "World" });
Console.WriteLine("Goodbye: " + goodbyeReply.Message);
Console.WriteLine("Hello, World!");
}
}
}