基于C#的GRPC

GRPC

gRPC(gRPC Remote Procedure Call)是由Google开发的高性能、跨语言的远程过程调用框架。它基于HTTP/2协议进行通信,支持多种编程语言,包括C++, C#, Java, Python等,使不同语言的应用程序可以通过远程调用相互通信。

1.关键特点和用途:

  1. 高性能:gRPC采用了HTTP/2协议,具有低延迟、高吞吐量和复用连接的特点。这使得它非常适合于需要高性能通信的应用程序。
  2. 跨语言支持:gRPC支持多种编程语言,允许不同语言的应用程序之间进行跨语言通信。这使得它在微服务架构中非常有用,因为不同的服务可以使用不同的编程语言实现。
  3. IDL(Interface Definition Language):gRPC使用ProtoBuf(Protocol Buffers)作为IDL,允许您定义服务接口和消息类型。这提供了强类型的通信,使得通信更加清晰和高效。
  4. 多种通信类型:gRPC支持不同类型的通信,包括请求-响应、服务器流、客户端流和双向流。这允许您选择最适合您应用程序需求的通信方式。
  5. 自动化代码生成:通过ProtoBuf定义服务接口和消息类型,gRPC工具会自动生成客户端和服务器端的代码,这样可以大大减少开发工作量。
  6. 认证和安全:gRPC支持各种认证和安全机制,包括SSL/TLS,OAuth等,以确保通信的安全性。
  7. 服务发现:gRPC可以与服务发现工具(如Consul、etcd)集成,从而实现动态服务发现和负载均衡。
  8. 可扩展性:gRPC是一个可扩展的框架,支持各种自定义扩展和中间件。

2.GRPC思路

Grpc类似于一种协议,遵循网络通讯,以.proto文件为协议模板进行客户端与服务端的交互开发,不限制客户端和服务端的代码语言风格.也可以在服务端与客户端使用不同的语言开发

3.编写.proto文件

在这里插入图片描述

// Protocol Buffers 语法版本 proto3 版本
syntax = "proto3";
// 定义了消息类型和服务的包名,类似于命名空间,用于避免命名冲突。
package Calculator;
// 定义了一个 gRPC 服务。在大括号中,您可以列出服务方法的定义。
service CalculatorService 
{
    // 定义了一个服务方法。rpc 表示定义一个远程过程调用(RPC)方法。MyMethod 是方法的名称,MyRequest 是输入参数类型,MyResponse 是输出参数类型。
    rpc MyMethod (MyRequest) returns (MyResponse);

  // 服务器流式方法
  rpc ServerStreamingMethod(Request1) returns (stream Response1);

  // 客户端流式方法
  rpc ClientStreamingMethod(stream Request2) returns (Response2);

  // 双向流式方法
  rpc BidirectionalStreamingMethod(stream Request3) returns (stream Response3);
}
message MyRequest 
{
    repeated int32 num = 10;
}
message MyResponse 
{
    repeated string strs = 10;
}

message Request1
{
    string Message = 1;
}
message Response1
{
    string Message = 1;
}
message Request2
{
    string Message = 1;
}
message Response2
{
    string Message = 1;
}
message Request3
{
    string Message = 1;
}
message Response3
{
    string Message = 1;
}
syntax = "proto3";

package Calculator;

import "Protos/Calculator.proto";

service FirstService {
    rpc MyMethod (MyRequest1) returns (MyResponse);
}
message MyRequest1 
{
    repeated int32 num = 10;
}

多个.proto文件间是可以调用的

在这里插入图片描述

4.添加.proto文件生成的文件编写服务端和客户端代码

在这里插入图片描述

.proto文件生成的文件位置 添加到客户端和服务端

5.服务端代码

using Calculator;
using Grpc.Core;

class CalculatorServiceImpl : CalculatorService.CalculatorServiceBase
{
    /// <summary>
    /// 发布响应
    /// </summary>
    /// <param name="request"></param>
    /// <param name="context"></param>
    /// <returns></returns>
    public override async Task<MyResponse> MyMethod(MyRequest request, ServerCallContext context)
    {
        MyResponse myResponse = new MyResponse();
        foreach (int i in request.Num)
        {
            myResponse.Strs.Add(i.ToString());
        }
        return myResponse;
    }

    /// <summary>
    /// 服务器流(Server Streaming)
    /// </summary>
    /// <param name="request"></param>
    /// <param name="responseStream"></param>
    /// <param name="context"></param>
    /// <returns></returns>
    public override async Task ServerStreamingMethod(Request1 request, IServerStreamWriter<Response1> responseStream, ServerCallContext context)
    {
        for (int i = 0; i < 10; i++)
        {
            Response1 response = new Response1 { Message = request.Message + $"Message {i}" };
            await responseStream.WriteAsync(response);
            await Task.Delay(500); // 模拟每秒发送一次数据
        }
    }

    /// <summary>
    /// 客户端流(Client Streaming)
    /// </summary>
    /// <param name="requestStream"></param>
    /// <param name="context"></param>
    /// <returns></returns>
    public override async Task<Response2> ClientStreamingMethod(IAsyncStreamReader<Request2> requestStream, ServerCallContext context)
    {
        string str = "";
        while (requestStream.MoveNext().Result)
        {
            str += requestStream.Current.Message;
            Console.WriteLine(requestStream.Current.Message);
        }
        return new Response2 { Message = str };
    }
    /// <summary>
    /// 双向流(Bidirectional Streaming)
    /// </summary>
    /// <param name="requestStream"></param>
    /// <param name="responseStream"></param>
    /// <param name="context"></param>
    /// <returns></returns>
    public override async Task BidirectionalStreamingMethod(IAsyncStreamReader<Request3> requestStream, IServerStreamWriter<Response3> responseStream, ServerCallContext context)
    {
        while (requestStream.MoveNext().Result)
        {
            // 处理客户端发送的请求
            Console.WriteLine(requestStream.Current.Message);
            Response3 response = new Response3 { Message = requestStream.Current.Message + "abc" };
            await responseStream.WriteAsync(response); // 发送响应
            await Task.Delay(500);
        }
    }

}

class Program
{
    static void Main(string[] args)
    {
        const int Port = 50051;

        Server server = new Server
        {
            Services = { CalculatorService.BindService(new CalculatorServiceImpl()) },
            Ports = { new ServerPort("localhost", Port, ServerCredentials.Insecure) }
        };

        server.Start();

        Console.WriteLine("Calculator server listening on port " + Port);
        Console.WriteLine("Press any key to stop the server...");
        Console.ReadKey();

        server.ShutdownAsync().Wait();
    }
}

6.客户端代码

using Calculator;
using Grpc.Core;

class Program
{
    const string ServerAddress = "localhost";
    const int Port = 50051;
    static void Main(string[] args)
    {
        MyMethod();
        ServerStreamingMethod();
        SelfIncreaseClient();
        BidirectionalStreamingMethod();

        Console.WriteLine("Press any key to exit...");
        Console.ReadKey();
    }
    /// <summary>
    /// 发布响应
    /// </summary>
    private static void MyMethod()
    {
        Channel channel = new Channel($"{ServerAddress}:{Port}", ChannelCredentials.Insecure);
        var client = new CalculatorService.CalculatorServiceClient(channel);
        MyRequest myRequest = new MyRequest { Num = { 1, 2, 3, 4 } };
        MyResponse myResponse = client.MyMethod(myRequest);
        Console.WriteLine($"Result: {myResponse.Strs}");
        channel.ShutdownAsync().Wait();
    }

    /// <summary>
    /// 服务器流(Server Streaming)
    /// </summary>
    private static void ServerStreamingMethod()
    {
        Channel channel = new Channel($"{ServerAddress}:{Port}", ChannelCredentials.Insecure);
        var client = new CalculatorService.CalculatorServiceClient(channel);
        Request1 request1 = new Request1 { Message = "ceshi" };
        AsyncServerStreamingCall<Response1> response1s = client.ServerStreamingMethod(request1);
        while (response1s.ResponseStream.MoveNext().Result)
        {
            Console.WriteLine(response1s.ResponseStream.Current.Message);
        }
        channel.ShutdownAsync().Wait();
    }

    /// <summary>
    /// 客户端流(Client Streaming)
    /// </summary>
    private static async void SelfIncreaseClient()
    {
        Channel channel = new Channel($"{ServerAddress}:{Port}", ChannelCredentials.Insecure);
        var client = new CalculatorService.CalculatorServiceClient(channel);
        var call = client.SelfIncreaseClient();
        for (int i = 0; i < 10; i++)
        {
            await call.RequestStream.WriteAsync(new Request2() { Message = $"第{i}个" });
            await Task.Delay(500);
        }
        await call.RequestStream.CompleteAsync();
        Console.WriteLine($"Result: {call.ResponseAsync.Result.Message}");
        channel.ShutdownAsync().Wait();
    }
    /// <summary>
    /// 双向流(Bidirectional Streaming)
    /// </summary>
    private static async void BidirectionalStreamingMethod()
    {
        Channel channel = new Channel($"{ServerAddress}:{Port}", ChannelCredentials.Insecure);
        var client = new CalculatorService.CalculatorServiceClient(channel);
        var call = client.BidirectionalStreamingMethod();
        for (int i = 1; i <= 5; i++)
        {
            // 发送请求
            await call.RequestStream.WriteAsync(new Request3 { Message = i.ToString() }); 
            await Task.Delay(500);
        }
        await call.RequestStream.CompleteAsync();

        while (call.ResponseStream.MoveNext().Result)
        {
            // 处理服务器发送的响应
            Console.WriteLine(call.ResponseStream.Current.Message);
        }
        channel.ShutdownAsync().Wait();
    }
}

7.Demo示例

在这里插入图片描述

在这里插入图片描述

2023/11/7

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
你好!关于C#中的gRPC长连接,我可以为你提供一些基本信息。 在C#中使用gRPC建立长连接,你需要按照以下步骤进行操作: 1. 首先,确保你已经安装了gRPC的NuGet包。你可以在Visual Studio中通过NuGet包管理器搜索并安装gRPC相关的包。 2. 在你的项目中,创建一个.proto文件来定义你的服务和消息类型。这个文件描述了你的API接口和数据结构。你可以使用gRPC提供的语法来定义你的服务和消息类型。 3. 使用gRPC工具生成C#代码。你可以使用gRPC提供的protoc工具来生成C#代码。运行以下命令来生成C#代码: ``` protoc -I <proto文件目录> --csharp_out <输出目录> --grpc_out <输出目录> --plugin=protoc-gen-grpc=<工具路径> <proto文件> ``` 这将生成与你的.proto文件对应的C#代码。 4. 在你的C#代码中,实现你的gRPC服务。你需要创建一个类来实现你在.proto文件中定义的服务接口。这个类将成为你的服务的实际实现。 5. 配置和启动gRPC服务器。你需要创建一个gRPC服务器并将你的服务类注册到服务器上。然后,通过调用服务器的Start方法来启动服务器。 6. 在客户端上建立长连接并调用服务。在客户端代码中,你需要创建一个gRPC通道来建立与服务器的连接。然后,通过通道创建一个客户端对象,并使用该对象来调用你的服务。 当你建立了一个gRPC通道后,它将维持一个长连接,使得客户端可以重复使用该通道与服务器进行通信。 这就是使用C#实现gRPC长连接的基本步骤。希望对你有所帮助!如果你有任何进一步的问题,请随时问我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值