基于C#的GRPC

news2024/11/23 15:12:10

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SPASS教程-入门

常用的统计工具 EXCEL 严格说来并不是统计软件&#xff0c;但作为数据表格软件&#xff0c;有一定统计计算功能。对于简单分析&#xff0c;Excel还算方便&#xff0c;但随着问题的深入&#xff0c;Excel就不那么“傻瓜”&#xff0c;需要使用函数&#xff0c;甚至根本没有相应…

​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​

软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】 课本里章节里所有蓝色字体的思维导图

Spire.Office for Java 8.10.2 同步更新Crk

Spire.Office for Java 是 E-iceblue 提供的企业级 Office Java API 的组合。它包括Spire.Doc for Java、Spire.XLS for Java、Spire.Presentation for Java、Spire.PDF for Java和Spire.Barcode for Java。 开发人员可以使用Spire.Office for Java在Java应用程序中执行各种办…

【electron】【附排查清单】记录一次逆向过程中,fetch无法请求http的疑难杂症(net::ERR_BLOCKED_BY_CLIENT)

▒ 目录 ▒ &#x1f6eb; 导读需求开发环境 1️⃣ Adblock等插件拦截2️⃣ 【失败】Content-Security-Policy启动服务器json-serverhtml中的meta字段 3️⃣ 【失败】https vs httpwebPreferences & allowRunningInsecureContent disable-features 4️⃣ 【失败】检测fetch…

技术分享 | app自动化测试(Android)--元素定位方式与隐式等待

元素定位是 UI 自动化测试中最关键的一步&#xff0c;假如没有定位到元素&#xff0c;也就无法完成对页面的操作。那么在页面中如何定位到想要的元素&#xff0c;本小节讨论 Appium 元素定位方式。 Appium的元素定位方式 定位页面的元素有很多方式&#xff0c;比如可以通过 I…

初识Java 17-2 反射

目录 转型前检查 构建例子&#xff1a;生成层次结构 优化Creator&#xff1a;使用类字面量 优化PetCounter&#xff1a;动态验证类型 更通用的递归计数 注册工厂 本笔记参考自&#xff1a; 《On Java 中文版》 转型前检查 当我们使用传统的类型转换&#xff0c;例如&…

实战!工作中常用的设计模式

文章目录 前言一、策略模式1.1、 业务场景1.2 、策略模式定义1.3、 策略模式使用1.3.1、一个接口&#xff0c;两个方法1.3.2、不同策略的差异化实现1.3.3、使用策略模式 二、责任链模式2.1、业务场景2.2、责任链模式定义2.3、责任链模式使用2.3.1、一个接口或者抽象类2.3.2、每…

11.7加减计数器,可置位~,数字钟分秒,串转并,串累加转并,24位串并128,流水乘法器,一些乘法器

信号发生器 方波&#xff0c;就是一段时间内都输出相同的信号 锯齿波就是递增 三角波就是先增后减 加减计数器 当mode为1则加&#xff0c;Mode为0则减&#xff1b;只要为0就输出zero 这样会出问题&#xff0c;因为要求是十进制&#xff0c;但是这里并没有考虑到9之后怎么办&a…

openvino学习(一)ubuntu20.04安装openvino2022

安装openvino2022要求 操作系统 Ubuntu 18.04 长期支持 (LTS)&#xff0c;64 位 Ubuntu 20.04 长期支持 (LTS)&#xff0c;64 位 软件 CMake 3.13 或更高版本&#xff0c;64 位 GCC 7.5.0&#xff08;适用于 Ubuntu 18.04&#xff09;或 GCC 9.3.0&#xff08;适用于 Ubunt…

工具介绍——第三方软件远程连接(工具:Rustdesk)

文章目录 前言一、使用工具二、开始演示1、拿下目标主机权限后上传文件2、运行目标主机上的rustdesk-1.1.9.exe文件3、目标主机上whoami查看现在的用户4、查找目标主机上连接的文件&#xff0c;并添加连接密码5、目标主机重启rustdesk的应用程序6、本地连接主机 前言 这里主要…

“第六十三天”

这两天怎么做的这么别扭&#xff0c;为什么我的vs 的strlen函数包括终止字符了&#xff1b; 哦哦&#xff0c;明白了&#xff0c;fgets函数读取在未达到指定字长&#xff0c;或者遇见空白符之前&#xff0c;会读取前面的所有字符&#xff0c;所以会读取换行符&#xff0c;而get…

康耐视深度学习ViDi-View菜单介绍

Accept View承认当前图片标注的有效性 Clear Marking 清除当前图片的标注特征 Clear Marking & Labels清除当前图片的标注特征和标签 Process处理当前图片 Edit ROI编辑检测的区域 Edit Regions编辑(标注)特征区域 Edit Mask 编辑遮挡(屏蔽)区域 Apply Mask To Tool将遮挡(…

杨辉三角(Java实现)

public class Demo09 {public static void main(String[] args) {//第一位和最后一位都为1//除了每行的第一列之外,其余的数为a[i][j]aa[i-1][j]a[i-1][j-1];int[][] arrays new int[10][10];for(int i 0;i<10;i){if(i0){ //第一行直接赋值为0arrays[i][0]1;continue;//重…

深入理解强化学习——多臂赌博机:基于置信度上界的动作选择

分类目录&#xff1a;《深入理解强化学习》总目录 因为对动作—价值的估计总会存在不确定性&#xff0c;所以试探是必须的。贪心动作虽然在当前时刻看起来最好&#xff0c;但实际上其他一些动作可能从长远看更好。 ϵ − \epsilon- ϵ−贪心算法会尝试选择非贪心的动作&#xf…

ZipInputStream解压报错java.lang.IllegalArgumentException: MALFORMED

背景 使用jdk自带的zip工具ZipInputStream&#xff0c;去读取使用winrar在中文windows制作出来的zip文件报错。 Exception in thread "main" java.lang.IllegalArgumentException: MALFORMEDat java.util.zip.ZipCoder.toString(ZipCoder.java:58)at java.util.zip…

Qwt QwtWheel绘制滚动轮

1.简介 QwtWheel 是一个用于实现滚动轮控件的类库。它基于 Qt 框架&#xff0c;并提供了一些方便的功能来处理滚动轮的事件和绘图。 QwtWheel 类继承自 QWidget类&#xff0c;用于定义滚动轮控件的通用行为。QwtWheel 添加了特定于滚动轮的功能。 QwtWheel 可以用于创建具有滚…

Spring Cloud之多级缓存

目录 传统缓存 多级缓存 JVM进程缓存 Caffeine 缓存驱逐策略 实现进程缓存 常用Lua语法 数据类型 变量声明 循环使用 定义函数 条件控制 安装OpenResty 实现Nginx业务逻辑编写 请求参数解析 实现lua访问tomcat JSON的序列化和反序列化 Tomcat的集群负载均衡 …

云表平台突破传统,企业级低代码让软件开发速度提升

随着数字化进程的加速推进&#xff0c;软件开发效率和成本的要求也在日益提高。在这个背景下&#xff0c;低代码技术的出现为企业软件开发提供了新的解决方案。低代码开发平台以其简单易用、高效灵活的特点&#xff0c;已经成为各行各业企业进行应用开发的首选工具。 企业中低代…

生成无损压缩png和有损压缩png的做法

作者:朱金灿 来源:clever101的专栏 为什么大多数人学不会人工智能编程?>>> png是一种常用的图像格式。png一般为无损压缩,但是可以是有损压缩的。 下图都是100x100的png图像,一个是无损压缩,一个是有损压缩。 看着效果基本一样,但是它们的大小相差很大,无损…

个体诊所管理系统电子处方软件,个体诊所人员服务软件,佳易王电子处方开单系统

个体诊所管理系统电子处方软件&#xff0c;个体诊所人员服务软件&#xff0c;佳易王电子处方开单系统 软件功能&#xff1a; 1、常用配方模板&#xff1a;可以自由添加配方分类&#xff0c;预先设置药品配方。 2、正常开药&#xff1a;可以灵活选择药品&#xff0c;用法用量&…