C++ grpc rpc取消示例学习

0 阅读4分钟

前言

本文根据github.com/grpc/grpc/t… 进行C++ grpc rpc取消示例学习运行。更多的是学习记录,水平不高,能力有限,错漏之处,还请见谅。欢迎友好讨论。

环境信息

  • 操作系统版本:ubuntu24.04
  • CMake版本:4.2.0
  • Git版本:2.43.0
  • GCC版本:gcc 13.3.0
  • OpenSSL版本: 3.0.13

在之前的教程mp.weixin.qq.com/s/50Tep3mq7… 中给出的是在Centos 7.6下的部署流程,现在我重装了操作系统为ubuntu 24.04,并且重新编译了grpc文件。相关二进制文件可以关注公众号 只做人间不老仙,后台发送 "grpc ubuntu 编译文件"获取我编译内容的压缩包 。

代码运行流程

编译

参考 mp.weixin.qq.com/s/50Tep3mq7… 克隆仓库 github.com/EarthlyImmo… 并配置grpc依赖。

配置好后,可以先修改一下 start_build.sh 中的gcc和g++的路径。

在blog_code/cancellation目录下执行:

./start_build.sh

完成编译。

运行

在blog_code/cancellation/build/server目录下运行服务器:

./server

另起一个终端,在blog_code/cancellation/build/client文件夹下运行客户端:

./client

运行结束后服务器也会输出:

代码大部分是copy的grpc官方的示例,这里对cmake文件和目录结构做了调整,对部分注释或者日志做了调整。

代码简单分析

代码使用hellworld示例,可以发现这个示例没有使用SSL认证。关于grpc 认证相关内容可以参考mp.weixin.qq.com/s/_54ixo8Dr…

还可以发现,这个示例使用的是异步回调API,且实现了一个双向流式 RPC。关于异步回调API更完整的介绍和示例可以参考mp.weixin.qq.com/s/4hU0XMHne… 相较于mp.weixin.qq.com/s/4hU0XMHne… 中的双向流式RPC,这个示例中的逻辑更为简单。

服务器代码简单分析

示例目的是为了演示取消rpc,所以当服务器读取或写入不成功的时候,直接认为是客户端取消了。

查看 mp.weixin.qq.com/s/4hU0XMHne… 中的例子,可以发现,当读取不成功时,服务器是当做客户端传输结束,服务器调用成功结束Finish(Status::OK)。而对服务器写入出错,官方示例中并没有处理,我在修改的时候加了一个异常处理,返回了Finish(Status(grpc::StatusCode::UNKNOWN,"Unexpected Failure"));

我们可以做个测试,将blog_code/cancellation/client/client.cpp修改为正常结束,而不是取消RPC:

按照 代码运行流程 一节编译运行,最终服务器输出:

客户端输出,

可以发现,即时正常结束,输出也会是RPC取消。为了兼容正常和取消两种情况,可以用CallbackServerContext::IsCancelled来区别是否是客户端取消。类似于下面:

修改后的代码在blog_code/cancellation/modify_server和blog_code/cancellation/modify_client中。修改后,编译运行,正常结束时,最终服务器输出:

客户端输出。

而当客户端取消RPC时,客户端输出与官方示例一致,服务器输出因为我加入了OnCancel接口,所以输出会多一条OnCancel日志。

这里还有一个问题,就是在服务器的读取失败时,除了客户端取消和客户端传输完成,还有别的场景吗?肯定是有的,比如网络异常等等,这种情况也一并调用Finish(grpc::Status::OK);可以吗?我问了AI,它说其他情况不管返回什么,大概率客户端都收不到了,所以状态码是什么无所谓了,但是Finish还是要调用,为了触发 OnDone 来销毁自己,避免内存泄露。这一点目前还想不清楚,后续再看。

客户端代码简单分析

客户端统计发送消息个数,在发送10条消息后触发取消RPC。

关于grpc rpc取消功能的一些说明

查看文档 grpc.io/docs/guides… 可以得到:

  • rpc不仅可以手动触发取消,截止时间(Deadline)过期和 I/O 错误也会触发取消
  • 对C++版本来说,可以实现级联取消,即服务A调用服务B,服务B再调用服务C,服务器A取消了对B的rpc调用,则B也会自动取消对C的rpc调用
  • 服务器端要主动检查取消状态并进行处理。例如服务器业务逻辑是一个耗时很长的计算任务,必须定期检查其当前服务的 RPC 是否已被取消,一旦发现已被取消,应立即停止处理
  • 取消是针对客户端而言的,服务器想终止rpc,返回错误状态或关闭流就好了

参考资料

欢迎关注公众号:只做人间不老仙