首页 > 编程语言 >在c#中使用gRPC通讯

在c#中使用gRPC通讯

时间:2024-04-10 17:13:42浏览次数:27  
标签:通讯 string c# gRPC static Mes using 服务端 客户端

参考 : C#封装GRPC类库及调用简单实例 - wtc87 - 博客园 (cnblogs.com)

包括:GRPC文件的创建生成、服务端和客户端函数类库的封装、创建服务端和客户端调用测试。

创建并生成GRPC服务文件

  1. 创建新项目控制台应用 , 项目名称(MgRPC)
  2. 安装三个nuget包 Google.Protobuf , Grpc.Core , Grpc.Tools
  3. 项目添加新建项,选择类,修改名称为Link.proto,添加后把Link.proto里面内容清空

定义Protocol

添加代码。测试实例为服务端和客户端传输字符串消息,只定义了一个方法(客户端调用,服务端重写),传输内容包括请求字符串和回复字符串。此处可自行定义。


syntax = "proto3";//proto3 是 Protocol Buffers 的第三个版本

// 指定了生成的 C# 代码的命名空间为 LinkService。当使用 protobuf 编译器 (protoc) 将这个 .proto 文件转换为 C# 代码时,生成的类将位于 LinkService 命名空间中
option csharp_namespace = "LinkService";

//定义了一个名为 Link 的 gRPC 服务。在 gRPC 中,服务是由一个或多个 RPC 方法组成的
service Link
{
	//定义了一个 RPC 方法。这个方法名为 GetMessage,它接受一个 Mes 类型的消息作为参数,
	//并返回一个 Mes 类型的消息。在 gRPC 中,客户端可以调用这个方法,并发送一个 Mes 消息给服务端,然后服务端会处理这个消息并返回一个 Mes 消息给客户端。
	rpc GetMessage(Mes) returns (Mes);
}

//定义了一个名为 Mes 的消息类型。在 protobuf 中,消息是由一系列字段组成的,每个字段都有一个名称、一个类型和一个标识符。
message Mes
{
    // 客户端发送
	// 定义了一个名为 StrRequest 的字段,类型为 string,标识符为 1。这个标识符在消息内部是唯一的,并且一旦分配就不能更改,因为它被用于序列化和反序列化过程中的字段识别。
	string StrRequest = 1;
	// 同样定义了一个名为 StrReply 的字段,类型为 string,标识符为 2。(服务端回复)
	string StrReply = 2;
}

设置Link.proto

右键Link.proto文件选择属性,生成操作选择如图:

生成cs文件代码

生成解决方案。在下图路径得到自动生成的两个类。

至此,获得GRPC服务需要的三个文件:Link.proto、Link.cs、LinkGrpc.cs。可以将这三个文件放在一个项目中直接使用,需要重写一下服务端方法、创建服务端和客户端的启动方法。但是如果不同的项目软件之间通讯需要各自如此开发。可以先封装成一个GRPC类库供其他项目直接调用。

服务端和客户端类库的封装

  1. 创建类库(.NET Framework)项目 , 项目名称(GrpcLink)
  2. 项目添加现有项,上面获得的三个文件(Link.cs , LinkGrpc.cs)。安装nuget包:Grpc.Core和Google.Protobuf。
  3. 创建两个类:LinkFunc用于放此类库可用于外部引用调用的方法。LinkServerFunc基于Link.LinkBase,用于重写在proto文件中定义的方法。

对于不同的项目,在客户端请求时,服务端要根据自身情况回复想回的内容,因此可以提供一个委托供外部自行开发回复函数。

在LinkFunc类中定义如下:

public static Func<string, string> ReplyMes;

LinkServerFunc

在LinkServerFunc类重写GetMessage方法如下

using Grpc.Core;
using LinkService;
using System.Threading.Tasks;
using static LinkService.Link;

namespace GrpcLink
{
    /// <summary>
    /// 重写在proto文件中定义的方法
    /// </summary>
    public class LinkServerFunc : LinkBase
    {
        public override Task<Mes> GetMessage(Mes request,ServerCallContext context)
        {
            Mes mes = new Mes();
            mes.StrReply = LinkFunc.ReplyMes(request.StrRequest);
            return Task.FromResult(mes);
        }
    }
}

LinkFunc

using Grpc.Core;
using LinkService;
using System;
using static LinkService.Link;

namespace GrpcLink
{
    public class LinkFunc
    {
        /// <summary>
        /// 用于服务端回复委托
        /// </summary>
        public static Func<string,string> ReplyMes;

        // 定义服务端和客户端
        public static Server LinkServer;
        public static LinkClient LinkClient;

        /// <summary>
        ///  服务端启动
        /// </summary>
        /// <param name="host"></param>
        /// <param name="port"></param>
        public static void LinkServerStart(string host,int port)
        {
            LinkServer = new Server
            {
                Services =
                    {
                        BindService(new LinkServerFunc())
                    },
                Ports = { new ServerPort(host,port,ServerCredentials.Insecure) }
            };
            LinkServer.Start();
        }

        /// <summary>
        ///  服务端关闭
        /// </summary>
        public static void LinkServerClose()
        {
            LinkServer?.ShutdownAsync().Wait();
        }

        /// <summary>
        /// 客户端启动
        /// </summary>
        /// <param name="strIp"></param>
        public static void LinkClientStart(string strIp)
        {
            Channel prechannel = new Channel(strIp,ChannelCredentials.Insecure);
            LinkClient = new LinkClient(prechannel);
        }

        /// <summary>
        /// 客户端发送消息函数
        /// </summary>
        /// <param name="strRequest"></param>
        /// <returns></returns>
        public static string SendMes(string strRequest)
        {
            Mes mes = new Mes();
            mes.StrRequest = strRequest;
            var res = LinkClient.GetMessage(mes);
            return res.StrReply;
        }
    }
}

生成引用库

生成解决方案。Debug中可以得到项目的dll文件GrpcLink.dll,其他项目可以引用使用了。

创建服务端和客户端调用测试

  1. 创建两个控制台(.NET Framework)项目 , 项目名称TestCilent , TestServer
  2. 将上述GrpcLink.dll文件分别放入两个项目中,并添加dll引用。 如果没有则安装nuget包:Grpc.Core和Google.Protobuf(此次测试没有安装)

TestServer服务端

using GrpcLink;
using System;
using System.Threading;

namespace TestServer
{
    /// <summary>
    /// 测试服务端
    /// </summary>
    internal class Program
    {
        static void Main(string[] args)
        {
            LinkFunc.LinkServerStart("127.0.0.1",9008);
            Thread.Sleep(500);
            LinkFunc.ReplyMes = ReplyMes;
            Console.ReadKey();
        }


        /// <summary>
        /// 接收到客户端信息后回复
        /// </summary>
        /// <param name="strRequest">客户端发送过来的内容</param>
        /// <returns></returns>
        public static string ReplyMes(string strRequest)
        {
            Console.WriteLine("接收到:" + strRequest);
            switch (strRequest)
            {
                case "1":
                return "Server识别到1";
                case "2":
                return "Server识别到2";
                case "测试":
                return "开始测试"; 
                case "连接服务端":
                return "true";
            }
            return "Server未识别到指定参数";
        }
    }
}

TestCilent客户端

using GrpcLink;
using System;
using System.Threading;

namespace TestCilent
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Thread.Sleep(2000);
            LinkFunc.LinkClientStart("127.0.0.1:9008");
            Console.WriteLine("连接服务端中");
            string conn = LinkFunc.SendMes("连接服务端");

            if (conn.Equals("true"))
            {
                Console.WriteLine("连接服务端成功!");


                for (int i = 0 ; i < 10 ; i++)
                {
                    Thread.Sleep(1000);
                    Console.WriteLine("输入测试内容..");
                    var line = Console.ReadLine();
                    var ret = LinkFunc.SendMes(line);
                    //获取到服务端返回的值
                    Console.WriteLine(ret);

                }
            }

            Console.WriteLine("连接失败 , 即将退出");
            Thread.Sleep(2000);
        }
    }
}

测试图例

标签:通讯,string,c#,gRPC,static,Mes,using,服务端,客户端
From: https://www.cnblogs.com/ouyangkai/p/18126438

相关文章

  • 安防视频监控/视频集中存储EasyCVR平台开启鉴权后设备列表不展示是为什么?
    安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快,EasyCVR基于云边端一体化架构,具有强大的数据接入、处理及分发能力,可提供视频监控直播、云端录像、云存储、录像检索与回看、智能告警、平台级联、云台控制、语音对讲、智能AI分析接入等功......
  • CF1466H 做题记录
    link非常adhoc的题,但是值得一练的好题!一眼下去,我们会发现这个条件真的太过于抽象,根本无法想象。注意到题目给了我们一个关键信息:一个排列组\(\{b_1,b_2,...,b_n\}\)对应唯一的好的分配方案。考虑建立图论模型:每个人的编号向最喜欢的物品编号连边,形成一棵内向基环树森林。......
  • 2024.3.30C笔记
    2024.3.30笔记1.转义字符intmain(){printf("abcd\b");//回退一个字符,隐藏\b算一个字符return0;}2.函数调用语句函数调⽤的时候,也会加上分号,就是函数调⽤语句#include<stdio.h>intAdd(intx,inty){returnx+y;}intmain(){printf("hehe\n")......
  • new mars3d.graphic.PolylineEntity({实现航线真实穿过山体或者模型的部分用虚线展示
    1.在官网示例中通过 newmars3d.graphic.PolylineEntity({实现航线真实穿过山体或者模型的部分用虚线展示效果2.示例地址:功能示例(Vue版)|Mars3D三维可视化平台|火星科技3.实现效果: 1.航线真实穿过山体或者模型的部分用虚线展示、并且是(真实穿过不是视线挡住那种),遮挡......
  • 发表一篇SCI论文到底有多难?审稿需要多久?
    SCI论文,是指被SCI即科学引文索引所收录的SCI期刊上刊登的学术期刊论文。发表SCI论文,对科研工作者的综合素质要求比较高,论文写好,将论文投稿出去后,也会有一个漫长的等待过程。一、SCI论文发表多难点1、不同研究方向研究难度不同,有的学科领域天生有优势容易出结果。例如在同样......
  • 一篇SCI论文一般多少字?
    1、一篇SCI投稿论文的具体字数,要根据刊物要求来定,不同的刊物之间,有些差别还是很大的,有的3-5千字左右,有的好几万字左右。一般来说,一篇SCI论文大概在3-5个版面左右。其次,发表一篇SCI投稿论文,并不是长篇大论,要把论文论点精简到位、观点明确,内容要切中要点,详略得当,只要把科研成果介......
  • SCI期刊版面费要多少?发SCI贵不贵?
    想要发表一篇SCI文章,可是没有那么简单,目前各大期刊的版面费都很贵,那么SCI的版面费到底有多贵呢?可以这样说,SCI期刊版面费绝对不亚于国内核心期刊,上万元的期刊版面费到现在也是很常见的了,因此很多作者觉得SCI论文发表难度是很大的。1、说到SCI收多少版面费,其实各个期刊都要求......
  • WSL2-Ubuntu Pytorch深度学习开发环境搭建
    安装Linux发行版删除现有Linux发行版wsl-l-vwsl--unregisterUbuntu从MicrosoftStore安装Linux发行版设置用户名和密码安装CUDACUDA(ComputeUnifiedDeviceArchitecture)是由NVIDIA推出的并行计算平台和编程模型。CUDAToolkit是由NVIDIA提供的一套用于GPU开发......
  • ROS中自定义全局算法规划器(c++)
     ros中编写一个全局路径规划器并集成为ros插件,加载到turtlebot3机器人平台上仿真验证参考资料:ROS中自定义全局规划器(上)_算法部署_哔哩哔哩_bilibili官网教程:navigation/Tutorials/WritingAGlobalPathPlannerAsPlugininROS-ROSWiki1.建立工作空间mkdir-pjps_......
  • uRPF(Unicast Reverse Path Forwarding,单播反向路径转发)
    uRPF(UnicastReversePathForwarding)概念和原理这是网络设备的一个安全特性,主要功能是用于防止基于源地址欺骗的网络攻击行为,说简单一点就是在IP数据包转发的时候不单基于目的地址查看路由表,对源地址同样进行查表,如未能查到路由(一般不是默认路由,但根据策略不同行为稍有区别),则......