前言
本文根据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,返回错误状态或关闭流就好了
参考资料
- 腾讯元宝-deepseek( yuanbao.tencent.com/ )和deepseek官方网站( www.deepseek.com/ )辅助
- github.com/grpc/grpc/t…
- grpc.io/docs/guides…