.Net Core微服务rpc框架GRPC通信基础

下面是详细的“.Net Core微服务rpc框架GRPC通信基础”的完整攻略,包括框架介绍、使用方法以及两条示例说明。

一、什么是GRPC?

GRPC是Google开源的跨语言高性能的RPC(Remote Procedure Call,远程过程调用)框架。它使用Protocol Buffers作为数据序列化方式,支持多种语言的实现。

GRPC可以让你像调用本地方法一样调用远程方法。它通过定义一份服务协议来描述服务,然后自动生成客户端和服务端的代码。客户端和服务端之间的通信是通过HTTP2实现的。相比于传统的HTTP1.1协议,HTTP2支持多路复用,头部压缩和双向流等特性,提高了网络传输的效率,这也是GRPC高性能的关键之一。

二、如何使用GRPC?

  1. 安装GRPC

在使用GRPC之前,我们需要在.NET Core项目中添加GRPC依赖。在Visual Studio中,打开NuGet包管理器并搜索“Grpc.AspNetCore”,然后选择安装该依赖。

  1. 创建GRPC服务

接下来,我们需要创建GRPC服务端。首先,定义一个服务接口并使用ProtoBuf进行标注:

syntax = "proto3";

option csharp_namespace = "GrpcServiceDemo";

package Math;

service MathService {
  rpc Add (AdditionRequest) returns (AdditionResponse);
}

message AdditionRequest {
  int32 number1 = 1;
  int32 number2 = 2;
}

message AdditionResponse {
  int32 result = 1;
}

其中,service MathService是定义的一个服务接口,Add是其中的一个方法,AdditionRequest是Add方法的入参,AdditionResponse是Add方法的返回值。

然后使用protobuf提供的编译器生成对应的服务代码。我们需要在项目根目录下创建一个proto文件夹,将上面的.proto文件存放在这个文件夹中。然后,在Visual Studio中打开“包管理器控制台”,并执行以下命令:

> dotnet tool install -g protobuf-net.Grpc.Tools
> cd src/
> mkdir grpc
> protoc -I ../proto --csharp_out ./grpc ../proto/Math.proto --grpc_out ./grpc --plugin=protoc-gen-grpc=./packages/Grpc.Tools.2.37.1/tools/windows_x64/grpc_csharp_plugin.exe

其中,proto参数指定.proto文件所在的文件夹,csharp_out参数指定生成C#代码的输出目录,grpc参数指定生成服务代码的输出目录,plugin参数指定使用的编译插件。

执行完成后,将生成的代码添加到项目中。

  1. 实现服务接口

将服务代码添加到项目后,我们需要实现定义的服务接口。在这个示例中,我们需要实现MathService服务接口中的Add方法,这个方法接收两个整数并返回它们的和。在完成实现后,将服务实现类注册到DI容器中,以便服务端能够调用它。

public class MathService : GrpcServiceDemo.Math.MathService.MathServiceBase
{
    public override Task<AdditionResponse> Add(AdditionRequest request, ServerCallContext context)
    {
        return Task.FromResult(new AdditionResponse
        {
            Result = request.Number1 + request.Number2
        });
    }
}

services.AddGrpc(options =>
{
    options.EnableDetailedErrors = true;
    options.MaxReceiveMessageSize = null;
    options.MaxSendMessageSize = null;
}).Services.AddServiceOptions<MathService>();

在上面的代码中,我们定义了一个MathService服务实现类,并实现了Add方法。服务实现类需要继承auto-generated类GrpcServiceDemo.Math.MathService.MathServiceBase,同时重写MathServiceBase中定义的Add方法。

最后,我们将服务实现类注册到DI容器中,并用AddGrpc方法指定我们的GRPC服务。在这个方法选项中,我们可以设置一些选项,例如启用详细错误信息,设置消息大小等。使用AddServiceOptions方法可以为GRPC服务添加自定义选项。

  1. 创建GRPC客户端

GRPC客户端使用的是Channel连接,我们需要创建一个GRPC Channel来连接GRPC服务端。可以使用以下代码创建Channel:

var channel = GrpcChannel.ForAddress("https://localhost:50051");

其中,ForAddress方法指定远程GRPC服务的地址和端口号。接下来,我们可以使用Channel创建GRPC客户端的实例,并调用服务接口提供的方法。

var client = new MathService.MathServiceClient(channel);
var response = client.Add(new AdditionRequest { Number1 = 1, Number2 = 2 });
int result = response.Result;

在上面的代码中,我们创建了一个MathService客户端实例,并调用了Add方法。Add方法接受一个AdditionRequest对象作为参数,并返回一个AdditionResponse对象。

三、GRPC示例说明

示例1:使用GRPC实现PingPong

这个示例演示了如何使用GRPC实现PingPong功能。PingPong是一种简单的RPC通信方式,客户端向服务端发送一条消息,服务端收到消息后返回同样的消息,客户端再次收到这条消息后就结束通信。

  1. 创建GRPC服务和客户端

首先,在服务端创建PingPong服务,定义Ping和Pong方法:

syntax = "proto3";

option csharp_namespace = "GrpcDemo";

package PingPong;

service PingPongService {
  rpc Ping (PingRequest) returns (PongResponse);
  rpc Pong (PongRequest) returns (PingResponse);
}

message PingRequest {
  string message = 1;
}

message PongRequest {
  string message = 1;
}

message PingResponse {
  string message = 1;
}

message PongResponse {
  string message = 1;
}

为了证明服务器和客户机代码之间的互操作性,下面的C#示例同时为服务端和客户端功能创建单个项目:

// Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddGrpc(options =>
    {
        options.EnableDetailedErrors = true;
    });
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGrpcService<PingPongService>();
    });
}

在这个示例中,我们在服务端设置了PingPongService服务,通过MapGrpcService方法将该服务注册到DI容器中。

接下来,在客户端创建PingPong客户端,调用Ping和Pong方法:

// Program.cs

var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new PingPongService.PingPongServiceClient(channel);

// Create a deadline for the call
var callOptions = new CallOptions(deadline: DateTime.UtcNow.AddSeconds(1));

var pingRequest = new PingRequest { Message = "Ping" };
var pongRequest = new PongRequest { Message = "Pong" };

var pingResponse = client.Ping(pingRequest, cancellationToken: CancellationToken.None, callOptions);
Console.WriteLine($"Ping: {pingResponse.Message}");

var pongResponse = client.Pong(pongRequest, cancellationToken: CancellationToken.None, callOptions);
Console.WriteLine($"Pong: {pongResponse.Message}");

在这个示例中,我们创建了一个PingPong客户端实例,并调用了Ping和Pong方法。Ping和Pong方法接受一个PingRequest或PongRequest对象作为参数,并返回一个PingResponse或PongResponse对象。

示例2:使用GRPC实现在线聊天室

这个示例演示了如何使用GRPC实现在线聊天室。聊天室是一种广泛使用的应用程序,它使用户能够在线聊天并交流。在这个示例中,我们使用GRPC和ASP.NET Core SignalR实现聊天室的核心功能。

  1. 创建GRPC服务和客户端

首先,在服务端创建Chat服务,定义AddUser,RemoveUser和SendMessage方法:

syntax = "proto3";

option csharp_namespace = "GrpcDemo";

package Chat;

service ChatService {
  rpc AddUser (AddUserRequest) returns (AddUserResponse);
  rpc RemoveUser (RemoveUserRequest) returns (RemoveUserResponse);
  rpc SendMessage (SendMessageRequest) returns (SendMessageResponse);
}

message AddUserRequest {
  string username = 1;
}

message AddUserResponse {
  bool result = 1;
  repeated string users = 2;
}

message RemoveUserRequest {
  string username = 1;
}

message RemoveUserResponse {
  bool result = 1;
  repeated string users = 2;
}

message SendMessageRequest {
  string message = 1;
}

message SendMessageResponse {
  bool result = 1;
  string message = 2;
}

接下来,在服务端实现Chat服务的接口:

public class ChatService : GrpcDemo.Chat.ChatService.ChatServiceBase
{
    private static IList<string> _users = new List<string>();
    private static readonly object _lockObj = new object();

    public override Task<AddUserResponse> AddUser(AddUserRequest request, ServerCallContext context)
    {            
        lock(_lockObj){
            if (!_users.Contains(request.Username)){
                _users.Add(request.Username);
            }
        }

        var response = new AddUserResponse{
            Result = true,
            Users = { _users }
        };

        return Task.FromResult(response);
    }

    public override Task<RemoveUserResponse> RemoveUser(RemoveUserRequest request, ServerCallContext context)
    {
        lock(_lockObj){
            _users.Remove(request.Username);
        }

        var response = new RemoveUserResponse{
            Result = true,
            Users = { _users }
        };

        return Task.FromResult(response);
    }

    public override async Task<SendMessageResponse> SendMessage(IAsyncStreamReader<SendMessageRequest> requestStream, ServerCallContext context)
    {
        var response = new SendMessageResponse {
            Result = true
        };

        var message = "";

        try
        {
            await foreach (SendMessageRequest item in requestStream.ReadAllAsync())
            {
                var username = context.RequestHeaders.FirstOrDefault(h => h.Key == "username")?.Value;
                message = $"{username}: {item.Message}";

                var hubContext = context.GetHttpContext().RequestServices.GetRequiredService<IHubContext<ChatHub>>();

                await hubContext.Clients.All.SendAsync("ReceiveMessage", message);

                response.Message = message;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
            response.Result = false;
            response.Message = "Message sending failed.";
        }

        return response;
    }
}

在服务端实现了AddUser,RemoveUser和SendMessage方法。我们使用一个静态变量_users来保存当前在线的用户,当用户连接聊天室时,我们将其添加到在线列表中。当用户离开聊天室时,从在线列表中删除该用户。当用户发送消息时,我们向所有在线用户广播该消息。

最后,我们将ChatService服务注册到DI容器中:

services.AddGrpc(options =>
{
    options.EnableDetailedErrors = true;
}).Services.AddServiceOptions<ChatService>();
  1. 创建SignalR Hub

接下来,我们需要使用SignalR创建一个Hub来处理客户端聊天请求。在这个示例中,我们创建ChatHub并实现ReceiveMessage方法,该方法接受来自客户端的消息并向所有其他客户端广播它:

public class ChatHub : Hub
{
    public async Task ReceiveMessage(string message)
    {
        await Clients.All.SendAsync("ReceiveMessage", message);
    }
}

在SignalR Hub中,我们使用“ReceiveMessage”作为事件名来发送和接收消息。

  1. 创建客户端

在客户端,我们首先需要通过GRPC连接到Chat服务,然后使用SignalR建立与聊天室的连接,并实现对ReceiveMessage事件的处理。以下是客户端代码:

using Grpc.Core;
using GrpcDemo.Chat;
using Microsoft.AspNetCore.SignalR.Client;

var channel = GrpcChannel.ForAddress("https://localhost:5001");

var client = new ChatService.ChatServiceClient(channel);

var username = "User_" + Guid.NewGuid().ToString("N");

var response = client.AddUser(new AddUserRequest { Username = username });

if (response.Result)
{
    var hubConnection = new HubConnectionBuilder()
                            .WithUrl("https://localhost:5001/chat")
                            .Build();

    hubConnection.On<string>("ReceiveMessage", (message) =>
    {
        Console.WriteLine(message);
    });

    await hubConnection.StartAsync();

    while (true)
    {
        var message = Console.ReadLine();

        if (string.IsNullOrEmpty(message))
            continue;

        var sendMessageClient = client.SendMessage();

        await sendMessageClient.RequestStream.WriteAsync(new SendMessageRequest
        {
            Message = message
        });

        await sendMessageClient.RequestStream.CompleteAsync();
    }
}

在上面的代码中,我们使用GRPC的客户端程序集生成GRPC Chat服务客户端,并将要发送的消息作为请求参数。使用SignalR客户端程序集,我们通过信号器在客户端上提供消息的接收功能,并将事件名称设置为"ReceiveMessage"来发送和接收消息。

以上就是使用GRPC实现PingPong和在线聊天室的示例说明。需要注意的是,GRPC的使用方式和.NET Core Web API非常不同,需要通过protobuf定义服务接口,并将服务代码添加到项目中。在实际应用中,我们可以结合使用GRPC和SignalR来实现高效的跨语言、跨平台的实时通信功能。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:.Net Core微服务rpc框架GRPC通信基础 - Python技术站

(0)
上一篇 2023年6月3日
下一篇 2023年6月3日

相关文章

  • Django视图层与模板层实例详解

    Django是一个用Python编写的Web框架,可以帮助开发者快速地构建Web应用程序。在Django中,视图层和模板层负责处理用户请求和生成响应。 Django视图层 Django视图层是处理用户请求并返回响应的代码片段。视图函数是指接受HTTP请求并返回HTTP响应的函数。在Django中,视图函数必须满足以下条件: 视图函数必须是Python函数 视…

    C# 2023年5月15日
    00
  • C# File.Exists – 判断文件是否存在

    File.Exists方法的作用与使用方法 File.Exists方法的作用 C#的File.Exists方法用于检查文件是否存在。当需要在代码中判断一个文件是否存在时,我们可以使用该方法来判断,避免了在后续文件操作中出现异常的情况。 File.Exists方法的使用方法 File.Exists方法属于C#的System.IO命名空间,使用该方法需要导入该命…

    C# 2023年4月19日
    00
  • .net中最简单的http请求调用(比如调用chatgpt的openAI接口)

    支持.Net Core(2.0及以上)/.Net Framework(4.5及以上),可以部署在Docker, Windows, Linux, Mac。 http请求调用是开发中经常会用到的功能,因为,很多第三方功能接口往往是通过http地址的形式提供的,比如:ChatGpt、OpenAI、短信服务、在线翻译、地图服务、语音智能、等…   .net中调用ht…

    C# 2023年5月5日
    00
  • .NET Core API之格式化输出对象OutputFormatter

    当我们在开发.NET Core API时,有时候需要在API返回结果中自定义格式,比如JSON格式化、XML格式化或者自定义格式化等。这时我们可以使用OutputFormatter来自定义输出格式,本文将详细讲解OutputFormatter的使用方法。 什么是OutputFormatter OutputFormatter是.NET Core框架中提供的一个…

    C# 2023年5月31日
    00
  • C#与.net高级编程 C#的多态介绍

    C#与.NET高级编程——C#的多态介绍 多态概念 多态是面向对象程序设计中的一个重要概念,指的是在一个类的不同实例对象上,相同的方法会产生不同的结果。C#实现多态机制的方式主要有两种:继承和接口。 多态的实现方式 继承多态 继承是C#中实现多态的一种方式。子类继承了父类的方法和属性,并且可以覆盖父类的方法。在调用子类的方法时,可以用父类的对象来调用,此时就…

    C# 2023年5月15日
    00
  • 答你所问 .NET小常识 方便学习asp.net的朋友

    让我为您详细讲解“答你所问 .NET小常识 方便学习asp.net的朋友”的完整攻略。 一、什么是.NET? .NET是由微软公司开发的一个软件框架,目的是为了开发Windows操作系统、Web 应用程序、移动设备应用程序等基于Windows平台的应用程序提供一个强大的编程支持环境。.NET框架包括一个大型库,所有这些库都使用 C#、VB.NET、C++ 等…

    C# 2023年5月31日
    00
  • Actionscript 3.0中Singleton实现 修正篇

    下面是详细讲解“Actionscript 3.0中Singleton实现 修正篇”的完整攻略。 前言 在开发中,Singleton(单例模式)模式的应用非常常见。它的特点是在一个程序中,某个类只能存在一个实例,这样可以保证它的属性、方法不会被重复使用或者多次创建实例造成的资源浪费等问题。Actionscript 3.0中也有它的实现方式,本篇文章将详细讲解如…

    C# 2023年6月6日
    00
  • 分享WCF文件传输实现方法—WCFFileTransfer

    WCF(Windows Communication Foundation)是一种用于构建分布式应用程序的框架。WCF可以用于实现各种功能,包括文件传输。本文将介绍如何使用WCF实现文件传输,并分享一个名为WCFFileTransfer的示例项目。 WCFFileTransfer项目介绍 WCFFileTransfer是一个使用WCF实现文件传输的示例项目。该…

    C# 2023年5月15日
    00
合作推广
合作推广
分享本页
返回顶部