前言

简单整理一下grpc。

正文

什么是grpc?

  1. 一个远程过程调用框架,可以像类一样调用远程方法。

这种模式一般来说就是代理模式,然后都是框架自我生成的。

  1. 由google 公司发起并开源,故而前面有个g。

grpc的特点:

  1. 提供几乎所有主流语言的实现,打破语言隔阂。

  2. 基于http/2,开放协议,收到广泛的支持,易于实现和集成

http/2 有个特点哈,就是更快,可以了解下,后续会专门整理关于http相关的,要等网络原理整理完后。

  1. 默认使用protocol buffers 序列化,性能相较于restful json好很多

  2. 工具链成熟,代码生成便捷,开箱即用

  3. 支持双向流式的请求和相应,对批量处理、低延迟场景友好

.net 生态对gRPC的支持情况:

  1. 提供基于httpClient 的原生框架的实现

  2. 提供了原生的ASP .net Core 集成库

  3. 提供完整的代码工具

  4. visual studio 和 visual Stuido Code 提供proto 文件的智能提示

    实践:

service 服务端:

.net core 在服务端使用的包:

  1. Grpc.AspNetCore

客户端使用的包:

  1. google.protobuf

  2. Grpc.Net.Client

  3. Grpc.Net.ClientFactory

  4. Grpc.Tools

通过工具会生成proto 文件。

proto 文件:

  1. 定义包、库名

  2. 定义服务"service"

  3. 定义输入输出模型"message"

gRPC 异常处理:

  1. 使用Grpc.Core.RpcException

  2. 使用Grpc.Core.Interceptors.Interceptor

grpc 的加密方式:

grpc 因为是http2,默认使用https证书。

也可以不使用证书,里面可以设置,如果设置了,那么就是不加密的。

  1. 注入服务
services.AddGrpcClient<Greeter.GreeterClient>(options =>
{
options.Address = new Uri("https://localhost:5001");
});
  1. 测试代码
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
Greeter.GreeterClient service = context.RequestServices.GetService<Greeter.GreeterClient>(); HelloRequest helloRequest = new HelloRequest();
var reply = await service.SayHelloAsync(helloRequest);
Console.Read();
});
endpoints.MapControllers();
});
  1. 结果

这样就可以调用了。

这里如果我们使用http://localhost:5000,那么访问会失败,显示协议不可用,不支持http1.1。

那么如果需要http的话,就需要配置一些http2了。

在服务端的配置文件中,这样写:

  "Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://*:5000"
},
"Https": {
"Url": "https://*:5001"
},
"Http2": {
"Url": "http://*:5002",
"Protocols": "Http2"
}
}
}

将http2的url设置为http://*:5002。

然后你就发现报错了:

这个问题也是比较简单的,因为http2默认使用加密,也就是应用解密的方式去解,自然就出错了。

那么需要这样:

AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport",true);

支持不使用加密方式的http2。如果是在内网内,可以不使用加密方式,这样更加流畅。

那么还有一种情况就是如果在有证书的情况下,那么我们的开发环境可能就跑不过了,因为本地使用自签名证书,通过不了验证。

下面是生成证书的powershell脚本,百度的。

# setup certificate properties including the commonName (DNSName) property for Chrome 58+
$certificate = New-SelfSignedCertificate `
-Subject 改成自己想要的标题不要带乱七八糟的符号(安装证书的时候会显示这个) `
-DnsName 友好域名 `
-KeyAlgorithm RSA `
-KeyLength 2048 `
-NotBefore (Get-Date) `
-NotAfter (Get-Date).AddYears(2) `
-CertStoreLocation "cert:CurrentUser\My" `
-FriendlyName "证书的友好名称,在IIS指定的时候显示Certificate for .NET Core" `
-HashAlgorithm SHA256 `
-KeyUsage DigitalSignature, KeyEncipherment, DataEncipherment `
-TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.1")
$certificatePath = 'Cert:\CurrentUser\My\' + ($certificate.ThumbPrint) # create temporary certificate path
$tmpPath = "C:\tmp"
If(!(test-path $tmpPath))
{
New-Item -ItemType Directory -Force -Path $tmpPath
} # set certificate password here
$pfxPassword = ConvertTo-SecureString -String "证书的密码" -Force -AsPlainText
$pfxFilePath = "c:\tmp\证书的名称.pfx"
$cerFilePath = "c:\tmp\证书的名称.cer" # create pfx certificate
Export-PfxCertificate -Cert $certificatePath -FilePath $pfxFilePath -Password $pfxPassword
Export-Certificate -Cert $certificatePath -FilePath $cerFilePath # import the pfx certificate
Import-PfxCertificate -FilePath $pfxFilePath Cert:\LocalMachine\My -Password $pfxPassword -Exportable # trust the certificate by importing the pfx certificate into your trusted root
Import-Certificate -FilePath $cerFilePath -CertStoreLocation Cert:\CurrentUser\Root # optionally delete the physical certificates (don’t delete the pfx file as you need to copy this to your app directory)
# Remove-Item $pfxFilePath
Remove-Item $cerFilePath

然后在服务端配置一下证书:

  "Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://*:5000"
},
"Https": {
"Url": "https://*:5001"
},
"Http2": {
"Url": "http://*:5002",
"Protocols": "Http2"
}
},
"Certificates": {
"Default": {
"Path": "self.cer",
"Password": "123456"
}
}
}

Certificates 配置了默认证书。

那么客户端请求一下https://localhost:5001.

返回:

那么这个时候无论证书验证是否成功,都返回true:

services.AddGrpcClient<Greeter.GreeterClient>(options =>
{
options.Address = new Uri("https://localhost:5001");
}).ConfigurePrimaryHttpMessageHandler(provider =>
{
var handle = new SocketsHttpHandler();
handle.SslOptions.RemoteCertificateValidationCallback = (a, b, c, d) => true;
return handle;
});

然后就可以访问了。

下面整理一下异常拦截器,如果我们服务端发生异常,我们希望有某种规律的错误发出。

测试异常:

public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
throw new Exception("异常信息");
return Task.FromResult(new HelloReply
{
Message = "Hello " + request.Name
});
}

通过异常拦截器过滤一下:

services.AddGrpc(options =>
{
options.EnableDetailedErrors = false;
options.Interceptors.Add<ExceptionInterceptor>();
});

具体异常拦截类:

public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
{
try
{
return await base.UnaryServerHandler(request, context, continuation);
}
catch (Exception ex)
{
//log 处理
Metadata entries = new Metadata();
entries.Add("message",ex.Message);
throw new RpcException(new Status(StatusCode.Unknown, "Unknown"), entries);
}
}

调试:

下一节实践一下用工具生成grpc 代码。

最新文章

  1. CODEVS 天梯 代码记录
  2. Oracle常用监控SQL
  3. 【C#进阶系列】00 序
  4. C++中构造函数详解及显式调用构造函数
  5. linux常见问题集锦-2
  6. c# web 缓存管理
  7. C#读写txt文件的两种方法介绍
  8. HD1285(拓扑排序)
  9. Katu Puzzle
  10. SFTP上传下载(C#)
  11. Eclipse 优化方法(经典收藏)
  12. CSS3实现时间轴效果
  13. RobotFramework自动化测试框架-移动手机自动化测试Input Text和Click Button关键字的使用
  14. Java常用代码总结
  15. php详细学习1
  16. 用户认证授权和Shiro入门
  17. Python的基本语法1
  18. Mysql 关键字的优先级 分组 多表联查
  19. git安装,windows下git bash默认目录更改
  20. BitSet的用法

热门文章

  1. 技能Get&#183;解决MSSQL Where查询中文数据存在但查不出来
  2. 解密华为云FusionInsight MRS新特性:一架构三湖
  3. golang:指针理解总结
  4. [bug] HMaster启动后几秒消失
  5. [Linux] Linux命令行与Shell脚本编程大全 Part.3
  6. [刷题] 79 Word Search
  7. Linux压力测试软件Stress安装及使用指南2
  8. 攻防世界(七)ics-06
  9. 7.1 useradd:创建用户
  10. 大数据学习之路——环境配置(2)——mysql 在linux 系统上安装配置