基于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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/120580.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis系列之常见数据类型应用场景

文章目录 String简单介绍常见命令应用场景 Hash简单介绍常见命令应用场景 List简单介绍常见命令应用场景 Set简单介绍常见命令应用场景 Sorted Set(Zset)简单介绍常见命令应用场景 Bitmap简单介绍常见命令应用场景 附录 Redis支持多种数据类型&#xff0c;比如String、hash、li…

Nat. Med. | 基于遗传学原发部位未知癌症的分类和治疗反应预测

今天为大家介绍的是来自Alexander Gusev团队的一篇论文。原发部位未知癌症&#xff08;Cancer of unknown primary&#xff0c;CUP&#xff09;是一种无法追溯到其原发部位的癌症&#xff0c;占所有癌症的3-5&#xff05;。CUP缺乏已建立的靶向治疗方法&#xff0c;导致普遍预后…

[java进阶]——方法引用改写Lambda表达式

&#x1f308;键盘敲烂&#xff0c;年薪30万&#x1f308; 目录 &#x1f4d5;概念介绍&#xff1a; ⭐方法引用的前提条件&#xff1a; 1.引用静态方法 2.引用构造方法 ①类的构造&#xff1a; ②数组的构造&#xff1a; 3.引用本类或父类的成员方法 ①本类&#xff1…

三大基础排序 -选择排序、冒泡排序、插入排序

排序算法 文章目录 冒泡排序算法步骤动图代码优化总结 选择排序算法步骤动图代码总结 插入排序算法步骤动图代码总结 排序算法&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。一般默认排序是按照由小到大即…

Windows下MSYS2下载与安装

下载地址&#xff1a; 官网下载地址 https://www.msys2.org/阿里云镜像下载 https://mirrors.aliyun.com/msys2/distrib/x86_64/https://mirrors.aliyun.com/msys2/distrib/x86_64/msys2-x86_64-20231026.exe?spma2c6h.25603864.0.0.12b92551XW5OSM官网下载 ![官网下载](htt…

uniapp u-tabs表单如何默认选中

首先先了解该组件&#xff1b;该组件&#xff0c;是一个tabs标签组件&#xff0c;在标签多的时候&#xff0c;可以配置为左右滑动&#xff0c;标签少的时候&#xff0c;可以禁止滑动。 该组件的一个特点是配置为滚动模式时&#xff0c;激活的tab会自动移动到组件的中间位置。 …

算法竞赛——数论(一),数论内容的介绍,基础数论

文章目录 一&#xff0c; 数论学习路线的介绍和相关建议1&#xff0c;建议学习人群 &#xff1a;2&#xff0c;建议学习时长3&#xff0c;学习路线的介绍1&#xff0c;基础数论2&#xff0c;组合数学3&#xff0c;计算几何 二&#xff0c;基础数论第一部分 —— 快速幂和快速幂…

Java算法(三): 判断两个数组是否为相等 → (要求:长度、顺序、元素)相等

Java算法&#xff08;三&#xff09; 需求&#xff1a; 1. 定义一个方法&#xff0c;用于比较两个数组是否相同2. 需求&#xff1a;长度&#xff0c;内容&#xff0c;顺序完全相同package com.liujintao.compare;public class SameArray {public static void main (String[] a…

一篇文章让你Docker从入门到精通

一篇文章让你Docker从入门到精通 Docker简介docker的3要素docker安装--centos7示例docker底层原理docker常用命令docker镜像原理数据共享--容器数据卷数据卷容器dockerfile解析Dockerfile实战一 使用dockerfile构建ubuntu镜像&#xff0c;并在里面安装vim及网络工具 一张图展示…

论文阅读:Ensemble Knowledge Transfer for Semantic Segmentation

论文地址&#xff1a;https://ieeexplore.ieee.org/document/8354272 项目及数据地址&#xff1a;https://github.com/ishann/aeroscapes 发表时间&#xff1a;2018年5月7日 语义分割网络通常以严格监督的方式学习&#xff0c;即它们在相似的数据分布上进行训练和测试。在域转…

EPLAN软件中的术语-主数据‘’技术分享

在EPLAN中&#xff0c;主数据(Master Data)这个词被经常、反复地提及&#xff0c;我曾经困惑了很长时间&#xff0c;不得要领。在EPLAN的帮助系统中&#xff0c;它列举了一部分内容&#xff0c;说这些这些就是主数据&#xff0c;但没有解释什么是主数据&#xff0c;除了上面这些…

怎么压缩jpg大小?快来收藏这款jpg压缩工具

不管是工作还是日常生活中&#xff0c;都免不了要用到许多图片&#xff0c;其中jpg图片格式是最常见的一种格式&#xff0c;那么小伙伴们知道怎么将jpg格式压缩大小吗&#xff1f;jpg压缩不仅可以为我们的设备节省空间&#xff0c;还能避免许多对图片大小有限制的平台&#xff…

阿里云双11优惠活动:2核2G3M云服务器1年99元,新老用户均可购买!

阿里云双11优惠活动正在火热进行中&#xff0c;阿里云推出了一款特价云服务器ECS&#xff0c;2核2G3M的配置1年仅需99元&#xff0c;新老用户均可购买&#xff0c;新购、续费同价&#xff01; 活动入口&#xff1a;传送门>>> 活动详情&#xff1a; 云服务器ECS&#…

2023年云计算的发展趋势如何?

混合云的持续发展&#xff1a;混合云指的是将公有云和私有云进行结合&#xff0c;形成一种统一的云计算环境。随着企业对数据隐私和安全性的要求越来越高&#xff0c;以及在数据存储和处理方面的需求不断增长&#xff0c;混合云正在逐渐成为主流。预计未来混合云将会继续保持高…

经典矩阵试题(一)

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、回型矩阵1、题目介绍2、思路讲解3、代码实现4、结果 二、蛇型矩阵1、题目介绍2、思路讲解…

[vue-router]vue3.x Hash路由前缀问题

[vue-router]vue3.x Hash路由前缀问题 问题描述问题分析 问题描述 是在本地开发时&#xff0c;使用的HASH路由&#xff0c;然后在偶然的情况下在/#/前添加了前缀&#xff0c;发现不影响本地的路由的使用&#xff1f;&#xff1f;&#xff1f;&#xff01;&#xff01;&#xf…

chatGPT培训老师AIGC培训讲师叶梓:大模型这么火,我们在使用时应该关注些什么?-6

以下为叶老师讲义分享&#xff1a; P25-P29 提示工程的模式 节省计算资源&#xff1a; 在微调过程中&#xff0c;不需要重新训练整个模型&#xff0c;因此可以节省计算资源。 提高特定任务上的性能&#xff1a; 通过微调&#xff0c;模型可以适应特定任务的语言特征和模式…

怎样在iOS手机上进行自动化测试

Airtest支持iOS自动化测试&#xff0c;在Mac上为iOS手机部署iOS-Tagent之后&#xff0c;就可以使用AirtestIDE连接设备&#xff0c;像连接安卓设备一样&#xff0c;实时投影、控制手机。iOS测试不仅限于真机测试&#xff0c;iOS模拟器也可以进行。Mac端上部署完成后还可以提供给…

linux继续循环案例测试ping网络,目录下的文件权限循环输出

第一&#xff1a;查看本机ip #ip addr 通过脚本访问本机ip1-100&#xff0c;是否可以ping通&#xff0c;并显示结果&#xff0c;上图 知识点 ping -c 数字1 -w 数字1&#xff0c;向目的ip发送1个数据包&#xff0c;等待1秒&#xff0c;无回复中止 &>/dev/null 知…

中远麒麟堡垒机SQL注入漏洞复现

简介 中远麒麟堡垒机用于运维管理的认证、授权、审计等监控管理&#xff0c;在该产品admin.php处存在SQL 注入漏洞。 漏洞复现 FOFA语法&#xff1a; body"url\"admin.php?controlleradmin_index&actionget_user_login_fristauth&username" 或者 c…