gRPC在.net中的使用

前言

  gRPC 是一种高性能、开源的远程过程调用(RPC)框架,基于 HTTP/2 协议,支持双向流、头部压缩等特性。它默认使用 Protocol Buffers(Protobuf)作为接口定义语言(IDL)和数据序列化格式,适用于微服务、实时通信等场景。

  我们可以结合常用的http服务来了解它。本质上讲,http服务是基于http协议,是一个应用层协议,RPC是基于TPC/IP,是一个传输层协议。应用层协议在传输层之上,所以RPC效率更高,所以RPC更适合内网调用,不必每次通信都要像http一样去3次握手什么的,减少了网络开销。

  

RPC架构

  一个完整的RPC架构里面包含了四个核心的组件,分别是Client ,Server,Client Stub以及Server Stub,这个Stub大家可以理解为存根。分别说说这几个组件:

    • 客户端(Client),服务的调用方。
    • 服务端(Server),真正的服务提供者。
    • 客户端存根,存放服务端的地址消息,再将客户端的请求参数打包成网络消息,然后通过网络远程发送给服务方。
    • 服务端存根,接收客户端发送过来的消息,将消息解包,并调用本地的方法。

 

 与http对比使用场景

1. 协议与数据格式

特性gRPCHTTP 接口(REST)
协议 基于 HTTP/2 基于 HTTP/1.1 或 HTTP/2
数据格式 使用 Protocol Buffers(Protobuf) 通常使用 JSON 或 XML
传输方式 二进制传输 文本传输

2. 性能

特性gRPCHTTP 接口(REST)
序列化效率 Protobuf 是二进制格式,序列化效率高 JSON/XML 是文本格式,序列化效率较低
传输效率 基于 HTTP/2,支持多路复用和头部压缩 HTTP/1.1 不支持多路复用,效率较低
延迟 低延迟,适合实时通信 延迟较高,适合简单请求-响应场景

3. 通信模式

特性gRPCHTTP 接口(REST)
通信模式 支持四种模式:
1. 一元 RPC
2. 服务器流 RPC
3. 客户端流 RPC
4. 双向流 RPC
仅支持请求-响应模式
实时通信 支持双向流,适合实时通信 不支持双向流,需通过轮询模拟

4. 开发与使用

特性gRPCHTTP 接口(REST)
接口定义 使用 Protobuf 定义服务接口,强类型 使用文档(如 OpenAPI)定义接口
代码生成 自动生成客户端和服务器代码 通常需要手动编写客户端代码
调试工具 工具较少,调试复杂 工具丰富(如 Postman)
跨语言支持 支持多种语言(C++, Java, Go, C# 等) 支持多种语言,但需要手动适配

5. 适用场景

特性gRPCHTTP 接口(REST)
微服务通信 适合高性能、低延迟的微服务通信 适合简单的服务间通信
实时通信 适合实时通信场景(如聊天、推送) 不适合实时通信
跨语言通信 适合异构系统之间的通信 适合简单的前后端通信
浏览器支持 需要 gRPC-Web 适配 原生支持

  

一个简单的gRPCDemo

服务端

创建order.proto

syntax = "proto3";

option csharp_namespace = "GrpcService";

package order;

service Order{
    rpc CreateOrder(CreateRequest) returns (CreateResult);
    rpc QueryOrder(QueryRequest) returns (QueryResult);
}
//创建订单请求参数
message CreateRequest {
string OrderNo = 1;
string OrderName=2;
double Price=3;
}

//创建订单返回结果
message CreateResult {
bool IsSuccess = 1; // 是否成功
string Message = 2; // 错误信息
}

//查询订单请求参数
message QueryRequest{
int32 Id=1;
}
//查询订单返回结果
message QueryResult{
int32 Id=1;
string OrderNo=2;
string OrderName=3;
double Price=4;
}

创建服务类

public class OrderService : Order.OrderBase
{
    private readonly ILogger<OrderService> _logger;
    public OrderService(ILogger<OrderService> logger)
    {
        _logger = logger;
    }
    /// <summary>
    /// 创建订单
    /// </summary>
    /// <param name="request"></param>
    /// <param name="context"></param>
    /// <returns></returns>
    public override Task<CreateResult> CreateOrder(CreateRequest request, ServerCallContext context)
    {
        //报存数据库 todo

        return Task.FromResult(new CreateResult
        {
            IsSuccess = true,
            Message = "订单创建成功"
        });
    }
    /// <summary>
    /// 查询订单
    /// </summary>
    /// <param name="request"></param>
    /// <param name="context"></param>
    /// <returns></returns>
    public override Task<QueryResult> QueryOrder(QueryRequest request, ServerCallContext context)
    {
        //查询数据库 //todo

        return Task.FromResult(new QueryResult
        {
            Id = request.Id,
            OrderNo = DateTime.Now.ToString("yyyyMMddHHmmss"),
            OrderName = "年货大礼包",
            Price = 699
        });
    }
}

添加服务依赖并配置管道

using GrpcService.Services;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddGrpc();

var app = builder.Build();

// Configure the HTTP request pipeline.
app.MapGrpcService<GreeterService>();
app.MapGrpcService<OrderService>();
app.MapGet("/", () => "hello world");
app.Run();

客户端

创建控制台程序

添加引用

Google.Protobuf
Grpc.Net.Client
Grpc.Tools

将服务端的order.proto拷贝过来,并在.csproj项目文件中添加配置项

<ItemGroup>
  <Protobuf Include="Protos\order.proto" GrpcServices="Client" />
</ItemGroup>

编译后自动生成代码

using Grpc.Net.Client;
using GrpcService;

string url = "https://localhost:7097";
using (var channel = GrpcChannel.ForAddress(url))
{
    var client = new Order.OrderClient(channel);
    var reply = await client.CreateOrderAsync(new CreateRequest
    {
        OrderName = "Order 1",
        OrderNo = "1",
        Price = 100
    });
    Console.WriteLine($"grpc客户端调用结果:{reply.Message},{reply.IsSuccess}");
    Console.Read();
}

 

IOC注入的方式调用gRPC

 添加注入

using GrpcClient.IOC;
using static GrpcService.Order;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddTransient<GrpcRequestTest>();
builder.Services.AddGrpcClient<OrderClient>(o =>
{
    o.Address = new Uri("https://localhost:7097");
}).ConfigureChannel(grpcOptions => { });

var app = builder.Build();
var grpcRequestTest = app.Services.GetRequiredService<GrpcRequestTest>();
grpcRequestTest.CreateOrder();
app.Run();
 public class GrpcRequestTest
 {
     private Order.OrderClient _orderClient;
     public GrpcRequestTest(Order.OrderClient orderClient)
     {
         _orderClient = orderClient;
     }
     public void CreateOrder()
     {
         var reply = _orderClient.CreateOrder(new CreateRequest()
         {
             OrderNo = DateTime.Now.ToString("yyyMMddHHmmss"),
             OrderName = "冰箱22款",
             Price = 1688
         });
         Console.WriteLine($"结果:{reply.IsSuccess},message:{reply.Message}");
         Console.ReadKey();
     }
 }

 

在webapi中加入gRPC服务

服务端

项目中往往需要同时提供webapi服务和gRPC服务。

创建一个webapi,添加Protos文件,注意要看下文件的生成属性。

 添加OrderService.cs

在program中添加Service和配置管道。

客户端

1、拷贝proto文件

2、修改项目文件添加配置项

<ItemGroup>
<Protobuf Include="Protos\order.proto" GrpcServices="Client" />
</ItemGroup>

3、配置并调用grpc服务和webapi

using GrpcServiceWithWebApi.Client;
using static GrpcServiceWithWebApi.Client.Order;

var builder = WebApplication.CreateBuilder(args);

//配置一个httpclient,请求地址为https://localhost:7097
builder.Services.AddHttpClient("GrpcServiceWithWebApi", c =>
{
    c.BaseAddress = new Uri("https://localhost:7095");
});
//配置一个grpcclient,请求地址为https://localhost:7097
builder.Services.AddGrpcClient<OrderClient>(o =>
{
    o.Address = new Uri("https://localhost:7095");
}).ConfigureChannel(grpcOptions => { });
var app = builder.Build();

app.MapGet("/", () =>
{
    //请求grpc服务
    var client = app.Services.GetRequiredService<OrderClient>();
    var reply = client.CreateOrder(new CreateRequest
    {
        OrderName = "Order 1",
        OrderNo = "1",
        Price = 100
    });
    var repcResult = $"grpc客户端调用结果:{reply.Message},{reply.IsSuccess}";
    //请求webapi服务
    var httpClient = app.Services.GetRequiredService<IHttpClientFactory>().CreateClient("GrpcServiceWithWebApi");
    var response = httpClient.GetAsync("/weatherforecast").Result;
    var webApiResult = response.Content.ReadAsStringAsync().Result;
    var webApiRel = $"{repcResult} <br/> {webApiResult}";
    return repcResult+webApiRel;
});

app.Run();

 代码地址:https://gitee.com/xiaoqingyao/g-rpcdemo.git

引用:

.NET Core(.NET6)中gRPC使用 - 包子wxl - 博客园
.NET Core中gRPC的使用

直观讲解一下 RPC 调用和 HTTP 调用的区别!

posted @ 2025-03-03 11:04  chenxizhaolu  阅读(301)  评论(0)    收藏  举报