• 基于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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    syntax = "proto3";
    
    package Calculator;
    
    import "Protos/Calculator.proto";
    
    service FirstService {
        rpc MyMethod (MyRequest1) returns (MyResponse);
    }
    message MyRequest1 
    {
        repeated int32 num = 10;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    多个.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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96

    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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87

    7.Demo示例

    在这里插入图片描述

    在这里插入图片描述

    2023/11/7

  • 相关阅读:
    C语言:指针二维数组排列
    proxy代理服务
    外包干了一个月,技术明显进步。。。。。
    数据结构——优先队列c++详解
    一文带你玩转offer-01
    基于HTML5的在线幻灯片编辑演示系统
    基于golang+uniapp+python 实现的一套A股提醒系统
    Neo4j-双向关系
    Veeam Backup Enterprise Manager身份验证绕过漏洞(CVE-2024-29849)
    vulnhub靶机darkhole
  • 原文地址:https://blog.csdn.net/qq1084517825/article/details/134272985