GRPC 是Google发布的一个开源、高性能、通用RPC(Remote Procedure Call)框架。提供跨语言、跨平台支持。以下以.NET Core 使用控制台、docker中演示如何使用GRPC框架。

 
 

软件版本

.net core :1.0.1

GRPC:1.0.1-pre1

 
 

 
 

1.定义服务

使用proto3语法定义一个服务,主要测试package、import、常用类型的测试,

proto3语法: https://developers.google.com/protocol-buffers/docs/proto3

 
 

定义一个result.proto

 
 

syntax = "proto3";

package App.RPC.Model;

message Response{

bool sucess=1;

string message=2;

}

 
 

定义RPCDemoService.proto文件如下:

syntax = "proto3";

package App.RPC.Service;

import "result.proto";

 
 

service RPCDemoService{

rpc Add(DemoRequest) returns (App.RPC.Model.Response){}

rpc GetById(DemoId) returns (DemoRequest){}

rpc Get(Search) returns (DemoList){}

}

message DemoId{

int32 Id=1;

}

 
 

message Search{

int32 page=1;

int32 size=2;

string query=3;

}

 
 

message DemoRequest{

string Id=1;

int32 CommentId=2;

bool IsDeleted=3;

}

 
 

message DemoList{

repeated DemoRequest details = 1;

}

 
 

2.将服务生成类文件:

项目引用nuget包Grpc.Tools 1.0.0 或通过命令安装这个程序包,然后找到文件路径

先配置packages\Grpc.Tools\1.0.0\tools\windows_x64\protoc.exe环境变量

protoc.exe --csharp_out=d:\grpcdemo\code\ --grpc_out=d:\grpcdemo\code\ --plugin=protoc-gen-grpc=yourpath\.nuget\packages\Grpc.Tools\1.0.0\tools\windows_x64\grpc_csharp_plugin.exe result.proto

protoc.exe --csharp_out=d:\grpcdemo\code\ --grpc_out=d:\grpcdemo\code\ --plugin=protoc-gen-grpc=yourpath\.nuget\packages\Grpc.Tools\1.0.0\tools\windows_x64\grpc_csharp_plugin.exe RPCDemoService.proto

 
 

3.创建.net core 类型项目App.RPCDemo

Project.json文件内容如下:

{

"version": "1.0.0-*",

"dependencies": {

"Grpc.Tools": "1.0.0"

},

"frameworks": {

"netstandard1.6": {

"imports": "dnxcore50",

"dependencies": {

"NETStandard.Library": "1.6.0",

"Grpc": "1.0.1-pre1",

"Grpc.Core": "1.0.1-pre1",

"Google.Protobuf": "3.1.0",

"System.Interactive.Async": "3.0.0"

}

}

}

}

 
 

4.创建服务端App.RPCDemoServer

因为要在docker 中进行测试,官方网站并没有docker 下的例子,也没有说这个rpc在生产环境中如何hosting; 通过查看.net core的host源码在Microsoft.AspNetCore.Hosting.Internal.ApplicationLifetime这个类文件有实现,把这个文件的内容直接copy过来

类的部分内容如下:

private readonly CancellationTokenSource _startedSource = new CancellationTokenSource();

private readonly CancellationTokenSource _stoppingSource = new CancellationTokenSource();

private readonly CancellationTokenSource _stoppedSource = new CancellationTokenSource();

 
 

/// <summary>

/// Triggered when the application host has fully started and is about to wait

/// for a graceful shutdown.

/// </summary>

public CancellationToken ApplicationStarted => _startedSource.Token;

 
 

/// <summary>

/// Triggered when the application host is performing a graceful shutdown.

/// Request may still be in flight. Shutdown will block until this event completes.

/// </summary>

public CancellationToken ApplicationStopping => _stoppingSource.Token;

 
 

/// <summary>

/// Triggered when the application host is performing a graceful shutdown.

/// All requests should be complete at this point. Shutdown will block

/// until this event completes.

/// </summary>

public CancellationToken ApplicationStopped => _stoppedSource.Token;

 
 

google Grpc中的server类型没有接口,定义一个接口Iserver

namespace App.RPC.Core

{

public interface IServer

{

void Start();

 
 

void Stop();

 
 

Status State { get; set; }

}

 
 

public enum Status

{

None,

Stop,

Running

 
 

}

}

 
 

在创建一个hosting 文件内容如下:

 
 

public static class RpcHostExtensions

{

public static void Run(this IServer server)

{

var done = new ManualResetEventSlim(false);

using (var cts = new CancellationTokenSource())

{

Action shutdown = () =>

{

if (!cts.IsCancellationRequested)

{

server.Stop();

Console.WriteLine("Rpc Service is shutting down...");

cts.Cancel();

}

done.Wait();

};

 
 

#if NETSTANDARD1_5

var assemblyLoadContext = AssemblyLoadContext.GetLoadContext(typeof(WebHostExtensions).GetTypeInfo().Assembly);

assemblyLoadContext.Unloading += context => shutdown();

#endif

Console.CancelKeyPress += (sender, eventArgs) =>

{

shutdown();

// Don't terminate the process immediately, wait for the Main thread to exit gracefully.

eventArgs.Cancel = true;

};

 
 

server.Run(cts.Token, "Rpc Service started. Press Ctrl+C to shut down.");

done.Set();

}

}

 
 

/// <summary>

/// Runs a web application and block the calling thread until token is triggered or shutdown is triggered.

/// </summary>

/// <param name="host">The <see cref="IWebHost"/> to run.</param>

/// <param name="token">The token to trigger shutdown.</param>

public static void Run(this IServer server, CancellationToken token)

{

server.Run(token, shutdownMessage: null);

}

 
 

private static void Run(this IServer server, CancellationToken token, string shutdownMessage)

{

if (server.State != Status.Running)

{

server.Start();

}

 
 

var applicationLifetime = new ApplicationLifetime();

if (!string.IsNullOrEmpty(shutdownMessage))

{

Console.WriteLine(shutdownMessage);

}

 
 

token.Register(state =>

{

((ApplicationLifetime)state).StopApplication();

},

applicationLifetime);

 
 

applicationLifetime.ApplicationStopping.WaitHandle.WaitOne();

 
 

}

}

 
 

实现服务RPCDemoImpl

public class RPCDemoImpl : RPCDemoService.RPCDemoServiceBase

{

public override Task<Response> Add(DemoRequest request, ServerCallContext context)

{

 

return Task.FromResult(new Response { Message = "成功" + context.Host + DateTime.Now.Ticks.ToString(), Sucess = true });

}

 
 

public override Task<DemoList> Get(Search request, ServerCallContext context)

{

var result = new DemoList();

result.Details.Add(new DemoRequest()

{

CommentId = 1,

Id = DateTime.Now.Ticks.ToString(),

IsDeleted = false

});

return Task.FromResult(result);

 
 

}

 
 

public override Task<DemoRequest> GetById(DemoId request, ServerCallContext context)

{

return Task.FromResult(new DemoRequest()

{

CommentId = request.Id,

Id = DateTime.Now.Ticks.ToString(),

IsDeleted = false

});

}

}

 
 

program文件如下:

public class Program

{

public static void Main(string[] args)

{

string host = "0.0.0.0";

int port = 9007;

var dic = Common.GetArgs(args);

if (dic != null && dic.Count > 0)

{

string tempHost;

string tempPort;

if (dic.TryGetValue("host", out tempHost))

{

host = tempHost;

}

if (dic.TryGetValue("port", out tempPort))

{

port = Convert.ToInt32(tempPort);

}

}

 
 

GrpcServer server = new GrpcServer

{

Services = { RPCDemoService.BindService(new RPCDemoImpl()) },

Ports = { new ServerPort(host, port, ServerCredentials.Insecure) }

};

Console.WriteLine("Google Grpc Starting");

foreach (var item in server.Ports)

{

Console.WriteLine(string.Format("RPC server {0} listening on port {1}", item.Host, item.Port));

}

server.Run();

 
 

}

}

 
 

编译发布后运行如下:

 
 

客户端程序

public static void Main(string[] args)

{

string host = "127.0.0.1";

string port = "9007";

long length = 10;

var dic = Common.GetArgs(args);

if (dic != null && dic.Count > 0)

{

string tempHost;

string tempPort, tempLength;

 
 

if (dic.TryGetValue("host", out tempHost))

{

host = tempHost;

}

if (dic.TryGetValue("port", out tempPort))

{

port = tempPort;

}

 
 

if (dic.TryGetValue("repeat", out tempLength))

{

length = Convert.ToInt64(tempLength);

}

}

 
 

Channel channel = new Channel(string.Format("{0}:{1}", host, port), ChannelCredentials.Insecure);

var client = new RPCDemoService.RPCDemoServiceClient(channel);

 
 

var stopwatch = Stopwatch.StartNew();

for (var i = 0; i < length; i++)

{

 
 

var reply = client.GetById(new DemoId() { Id = i });

Console.WriteLine("receive" + JsonConvert.SerializeObject(reply));

}

stopwatch.Stop();

 
 

Console.WriteLine(string.Format("repeat={0}, time={1} Milliseconds, time/repeat={2}", length, stopwatch.ElapsedMilliseconds, stopwatch.ElapsedMilliseconds / (float)length));

Console.ReadKey();

 
 

channel.ShutdownAsync().Wait();

 
 

}

 
 

编译发布运行如下:

 
 

 
 

 
 

Centos 7测试如下:

服务端

[demo@node139 App.RPCDemoServer]$ docker run --name rcpdemo -d -p 9007:9007 grpcemoserver

966b44acb2e0757c45b7dcf2d865e424dc764e50844e312ef2ea374999992a55

客户端

[demo@node139 App.RPCDemoClient]$ dotnet App.RPCDemoClient.dll host=192.168.190.139 port=9007 repeat=1

receive{"Id":"636138810040717530","CommentId":0,"IsDeleted":false}

 
 

docker中演示和源码地址:https://github.com/yjpgfwxf/App.GRPCDemo.NetCore

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

 
 

.net core 用grpc实现微服务的更多相关文章

  1. ASP.NET Core基于K8S的微服务电商案例实践--学习笔记

    摘要 一个完整的电商项目微服务的实践过程,从选型.业务设计.架构设计到开发过程管理.以及上线运维的完整过程总结与剖析. 讲师介绍 产品需求介绍 纯线上商城 线上线下一体化 跨行业 跨商业模式 从0开始 ...

  2. 微服务优化之使用gRPC做微服务的内部通信

    使用gRPC做微服务的内部通信 gRPC是一个由Google开源的远程服务调用框架,具有多路复用和双向流式通信的特性. 大家好,在本文中将为大家介绍为什么我们应该使用gRPC代替RESTful或JSO ...

  3. 使用 ASP.NET Core 3.1 的微服务开发指南

    使用 ASP.NET Core 3.1 的微服务 – 终极详细指南 https://procodeguide.com/programming/microservices-asp-net-core/ A ...

  4. 如何基于gRPC沟通微服务框架

    本文我们来讲解一下如何使用 gRPC构建微服务,gRPC是一个开源框架,可用于构建可扩展且高性能的微服务并创建服务之间的通信. 背景 随着企业越来越多地转向微服务,对构建这些微服务的低延迟和可扩展框架 ...

  5. AspNet Core Api Restful 实现微服务之旅 (一)

    (一)了解微服务(二)搭建VS项目框架  (三)创建AspNet Core Api VS2017 安装包   链接:https://pan.baidu.com/s/1hsjGuJq 密码:ug59 创 ...

  6. python3和grpc的微服务探索实践

    对于微服务的实践,一般都是基于Java和Golang的,博主最近研究了下基于Python的微服务实践,现在通过一个简单的服务来分析Python技术栈的微服务实践 技术栈:Python3 + grpc ...

  7. grpc 实现微服务生态笔记

    微服务的发展可谓是一波三折,一代一代经历和N多技术成果,grpc只是其中一个,因为其东家是google,明显比较稳定.加上其强大的文档和技术支持和跨平台的支持,在企业级应用上有很大的可信任感,所以也有 ...

  8. 微服务架构攀登之路(四)之使用gRPC构建微服务

    做一个处理用户信息的微服务 客户端通过用户名,可以从服务端查询用户的基本信息 gRPC proto user.proto 定义客户端请求.服务端响应的数据格式 user.pb.go 自动生成的,为数据 ...

  9. .NET Core 实践一:微服务架构的优点(转)

    微服务现在已经是各种互联网应用首选的云架构组件,无论是 BAT 还是 滴滴.美团 ,微服务都是重要的一环. 相对于微服务,传统应用架构有以下缺点: 1. 业务代码混杂,团队成员职责边界不清,团队协作体 ...

随机推荐

  1. JavaScript作用域链

    之前写过一篇JavaScript 闭包究竟是什么的文章理解闭包,觉得写得很清晰,可以简单理解闭包产生原因,但看评论都在说了解了作用域链和活动对象才能真正理解闭包,起初不以为然,后来在跟公司同事交流的时 ...

  2. Design Patterns Simplified - Part 2 (Singleton)【设计模式简述--第二部分(单例模式)】

    原文链接: http://www.c-sharpcorner.com/UploadFile/19b1bd/design-patterns-simplified-part-2-singleton/ De ...

  3. MVC学习系列10---验证系列之服务器端验证

    这篇文章,我将会说到,使用数据注解API来进行服务端验证.ASP.NET MVC 框架在执行的时候,验证所有传递到控制器的数据,如果验证失败就把错误消息,填充到ModelState对象中,并且把这个对 ...

  4. listview控件及其与数据库的连接

    一.显示数据 1.视图 -----小三角--视图-Details,该选项最常用,选中之后会以表格样式呈现. 2.设置列头 ----右键--编辑列 --添加 先编辑列,再编辑项 编辑列右边的属性:Tex ...

  5. 使用AOP+Annotation实现操作日志记录

    先创建注解 OperInfo @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @ ...

  6. C标准头文件<signal.h>

    信号即异常,或者理解为中断,一个进程接收到一个信号,如果没有处理机制,就会按照默认的处理方式进行处理,而默认的处理方式通常是终止当前进程或忽略该信号.当然,程序也可以编写相应的处理信号的函数,一旦接收 ...

  7. spring入门(三)【事务控制】

    在开发中需要操作数据库,进行增.删.改操作的过程中属于一次操作,如果在一个业务中需要更新多张表,那么任意一张表的更新失败,整个业务的更新就是失败,这时那些更新成功的表必须回滚,否则业务会出错,这时就要 ...

  8. 使用jenkins配置.net mvc网站进行持续集成二

    上一篇使用jenkins配置.net mvc网站进行持续集成一只是简单介绍了jenkins构建站点到本地服务器,这一篇,就来讲解如何部署站点到指定的服务器上面. 1.IIS远程发布配置 1.在服务器管 ...

  9. 变通实现微服务的per request以提高IO效率(三)

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  10. ADO.NET数据库参数化

    数据库参数化传递可以增强数据的安全性,但却会降低开发效率,为此创建了如下函数以解决这个问题: public static string PrepareParameter(string sql, out ...