一. gRPC通讯简介

1.gRPC是一种高性能、开源和通用的RPC(远程过程调用)框架,由Google主导开发。gRPC基于HTTP/2协议传输,采用Protocol Buffers(protobuf)作为接口描述语言。它专为在微服务架构下进行服务器与服务器之间的通信而设计,支持各种编程语言,包括C#, Java, Python, Go等。

2.gRPC是基于HTTP/2协议传输,也属于常规的7层通讯协议,所以对于数据的传输效率并没有很大的提升。而采用Protocol Buffers进行序列化和反序列化提升了数据的序列化和反序列化性能。

二. 优缺点

gRPC通信协议具有一系列显著的优点,但也伴随着某些局限性和缺点。下面概述了gRPC的主要优缺点:

优点:

  1. 性能高效: 基于HTTP/2支持长连接、多路复用、服务器推送等,减少延迟,提高吞吐量。二进制传输比传统的文本协议(如HTTP/1.1)更高效。

  2. 跨语言支持: 具有宽泛的语言支持,可以容易地在不同的编程语言之间进行通信。

  3. 强类型契约: 使用Protocol Buffers强类型系统定义服务接口和消息,一旦定义完成并通过编译,编译器就可以对类型错误进行检查,从而减少运行时错误。

  4. 多种通信模式: 支持多种RPC模式,包括简单的请求-响应模式、服务器流式、客户端流式和双向流式。

  5. 集成认证、跟踪、健康检查等: 支持拦截器和中间件,使得集成第三方功能和库变得非常容易。

  6. 清晰的API契约: 通过.proto文件定义,可以清晰地理解服务的结构,也方便自动生成代码和文档。

  7. 简化数据序列化: Protocol Buffers是一个高效的结构化数据表示格式,可以简化数据的序列化和反序列化过程。

缺点:

  1. 浏览器支持有限: 因为gRPC基于HTTP/2,而且通信使用的是自定义的二进制协议,所以不同于可以直接用HTTP请求实现的RESTful APIs,gRPC在浏览器中不是那么容易接入和使用,虽然有gRPC-Web解决方案,但存在一些限制,如需要特定的代理支持。

  2. 生态系统: 虽然支持许多语言,但是部分语言的生态系统(如工具链和第三方库支持)可能没有RESTful APIs那么成熟。

  3. 普遍认知和理解程度: 相比于REST,对于新接触的开发者来说,gRPC和Protocol Buffers可能存在更陡峭的学习曲线。

  4. 防火墙与代理限制: 一些企业级环境的防火墙和代理可能默认不支持HTTP/2,从而需要额外的配置工作。

  5. 调试与跟踪: 由于gRPC使用二进制协议,导致网络调试和跟踪比基于文本的协议更为复杂。

  6. 版本兼容性管理: 管理.proto文件的版本兼容性需要严格的约定,否则可能由于服务定义的变更导致客户端和服务器端不匹配的问题。

  7. 运维复杂度: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!");
        }
    }
}
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐