尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

MongoDB 仓库内 gRPC C++ 官方示例完全指南:从 Hello World 到 Route Guide 四类 RPC 实战

MongoDB 仓库内 gRPC C++ 官方示例完全指南:从 Hello World 到 Route Guide 四类 RPC 实战 MongoDB 仓库内 gRPC C 官方示例完全指南从 Hello World 到 Route Guide 四类 RPC 实战【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo导读本文以 gRPC C Examples 索引文档 为骨架完整讲解 MongoDB 仓库所 vendored 的 gRPC 发行版中两个核心 C 示例——Hello World 与 Route Guide前者带你完成构建 gRPC → 运行第一个 Hello World 应用的快速起步后者通过一个真实的地理位置服务覆盖 gRPC 全部四种 RPC 通信模型简单 RPC、服务端流、客户端流、双向流。读完本文你将掌握在src/third_party/grpc/dist下编译运行这些示例的方法、服务端与客户端的完整代码骨架以及如何依据源码读懂每个示例的实现要点。一、示例目录整体定位两个入口一套完整生态examples/cpp/README.md是 gRPC C 示例的入口索引全文结构非常清晰它不重复罗列细节而是把读者导向两个最重要的起点Hello World如果你迫不及待想跑通第一个 gRPC 示例应先阅读它的构建与运行说明对应 gRPC 官方文档的 C Quick Start 教程示例源码位于 helloworld 目录Route Guide如果你想要一份系统的 gRPC 入门教程则应以它为教材对应 gRPC 官方文档的 gRPC Basics 教程示例源码位于 route_guide 目录。索引文档同时指出目录下其他示例各自带有独立的 README 文件可按需查看。从目录清单见 examples/cpp可以看到除上述两个基础示例外还沉淀了 20 余个覆盖高级主题的独立示例子目录包括子目录主题子目录主题auth/认证与鉴权interceptors/拦截器cancellation/RPC 取消keepalive/连接保活cmake/CMake 构建load_balancing/负载均衡compression/消息压缩metadata/元数据传递csm/可观测性服务网格multiplex/多服务多路复用deadline/超时截止时间orca/自定义负载报告debugging/调试手段otel/OpenTelemetry 集成default_event_engine/默认事件引擎reflection/服务反射error_details/错误详情retry/重试策略error_handling/错误处理systemd_socket_activation/systemd 套接字激活flow_control/流控unix_abstract_sockets/Unix 抽象套接字gcp_observability/GCP 可观测性wait_for_ready/连接就绪等待generic_api/泛型 APIxds/xDS 控制面集成health/健康检查这些示例共同构成了一套从第一个程序到生产级特性的完整学习路径。二、Hello World跑通你的第一个 gRPC C 程序helloworld 目录的 README 内容极其精炼它只做一件事——把读者引导至 gRPC 官方的 C Quick Start 教程那里提供了完整的构建 gRPC 运行 Hello World步骤。虽然 README 本身只有几行但目录内的源码却是理解 gRPC C 同步 API 的最佳起点。2.1 示例提供了哪些程序形态从 helloworld/BUILD 的cc_binary目标可以看出这个示例不止一个程序而是围绕同一份Greeter服务封装了多种编程模型greeter_server/greeter_client基于同步 API的一元 RPCUnary RPCgreeter_callback_server/greeter_callback_client基于回调 APICallback APIgreeter_async_server/greeter_async_client/greeter_async_client2基于异步 APIAsync APIxds_greeter_server/xds_greeter_client接入 xDS 控制面的 Greeter 服务。所有目标都依赖//:grpc核心库与 examples/protos 中生成的 helloworld 服务代码并统一使用 Abseil 的flags、log库解析命令行参数与初始化日志。其中服务端目标额外链接了//:grpc_reflectiongRPC 服务反射插件客户端目标则不需要。2.2 服务端实现四步搭起一个服务greeter_server.cc 是理解 gRPC C 服务端的最小范例核心逻辑只有几十行ABSL_FLAG(uint16_t, port, 50051, Server port for the service); class GreeterServiceImpl final : public Greeter::Service { Status SayHello(ServerContext* context, const HelloRequest* request, HelloReply* reply) override { std::string prefix(Hello ); reply-set_message(prefix request-name()); return Status::OK; } }; void RunServer(uint16_t port) { std::string server_address absl::StrFormat(0.0.0.0:%d, port); GreeterServiceImpl service; grpc::EnableDefaultHealthCheckService(true); grpc::reflection::InitProtoReflectionServerBuilderPlugin(); ServerBuilder builder; builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); builder.RegisterService(service); std::unique_ptrServer server(builder.BuildAndStart()); std::cout Server listening on server_address std::endl; server-Wait(); }可以拆解出四个固定步骤继承生成的 Service 基类GreeterServiceImpl继承自Greeter::Service覆写SayHello方法完成拼接问候语前缀的业务逻辑并返回Status::OK——这就是 gRPC 服务端开发的全部业务面配置监听地址与凭据ServerBuilder::AddListeningPort绑定0.0.0.0:50051本示例未启用任何认证机制InsecureServerCredentials端口通过--port命令行 flag 控制默认 50051注册服务并启动RegisterService注册服务实现BuildAndStart组装并启动服务端阻塞等待server-Wait()让主线程挂起等待其他线程负责关闭服务。值得一提的细节第 62–63 行分别调用了EnableDefaultHealthCheckService(true)与InitProtoReflectionServerBuilderPlugin()前者开启 gRPC 内置的默认健康检查服务后者注册 protobuf 反射插件——这也是 BUILD 文件中服务端需要额外链接grpc_reflection的原因。启动后即可通过grpcurl等工具反射式地查询服务定义。2.3 客户端实现Channel Stub RPC 调用三件套greeter_client.cc 则展示了客户端的标准姿势ABSL_FLAG(std::string, target, localhost:50051, Server address); class GreeterClient { public: GreeterClient(std::shared_ptrChannel channel) : stub_(Greeter::NewStub(channel)) {} std::string SayHello(const std::string user) { HelloRequest request; request.set_name(user); HelloReply reply; ClientContext context; Status status stub_-SayHello(context, request, reply); if (status.ok()) { return reply.message(); } else { std::cout status.error_code() : status.error_message() std::endl; return RPC failed; } } private: std::unique_ptrGreeter::Stub stub_; }; int main(int argc, char** argv) { absl::ParseCommandLine(argc, argv); std::string target_str absl::GetFlag(FLAGS_target); GreeterClient greeter( grpc::CreateChannel(target_str, grpc::InsecureChannelCredentials())); std::string user(world); std::string reply greeter.SayHello(user); std::cout Greeter received: reply std::endl; return 0; }三个关键对象各司其职Channelgrpc::CreateChannel(target, creds)建立到服务端端点的连接模型目标地址由--target指定默认localhost:50051本示例使用InsecureChannelCredentials()表示不认证通道StubGreeter::NewStub(channel)生成的客户端代理负责把方法调用封装为网络 RPCClientContext一次 RPC 的上下文容器可用于向服务端传递额外元数据或调整调用行为。SayHello中status.ok()的判断是 gRPC 客户端处理错误的标准范式成功则取出reply.message()失败则打印error_code与error_message。三、Route Guide覆盖全部四种 RPC 模型的系统教程如果说 Hello World 只展示了最简单的一元 RPC那么 route_guide 示例 就是一份完整的 gRPC C 入门教材——它用一个地理路线导游服务把 gRPC 的四种 RPC 模型全部串了起来。3.1 示例定位与配置项README 明确说明本目录中的文件是 gRPC BasicsC 版教程所使用的示例代码。除此之外它还给出了两个关键信息1proto 定义位置RouteGuide 服务的 proto 定义位于 examples/protos/route_guide.proto不在示例目录内而是与所有语言示例共享。2db_path命令行参数服务端接受一个命令行参数参数含义默认值Bazel 构建默认值非 Bazel 构建db_path包含地理数据库的 JSON 文件路径examples/cpp/route_guide/route_guide_db.jsonroute_guide_db.json该参数的实际解析逻辑位于 helper.cc通过ABSL_FLAG定义db_path并根据BAZEL_BUILD宏区分两套默认值。GetDbFileContent负责读取文件内容若打开失败会记录LOG(ERROR)并abort()。服务端与客户端的main函数如 route_guide_callback_server.cc都会调用routeguide::GetDbFileContent(argc, argv)来加载这份数据库——客户端也需要它因为要从中随机选取参观点。示例自带的真实数据文件位于 route_guide_db.json。3.2 运行示例README 给出了使用 gRPC 自带 Bazel 封装脚本运行服务端与客户端的命令在 gRPC 发行版根目录下执行# 启动服务端默认监听 0.0.0.0:50051 $ tools/bazel run examples/cpp/route_guide:route_guide_callback_server # 另开终端启动客户端 $ tools/bazel run examples/cpp/route_guide:route_guide_callback_client对应的 Bazel 目标定义在 route_guide/BUILD 中。值得注意的是客户端在main中通过grpc::CreateChannel(localhost:50051, grpc::InsecureChannelCredentials())硬编码连接地址因此默认情况下客户端与服务端需运行在同一台机器上。3.3 proto 定义四种 RPC 模型的教科书route_guide.proto 是整个示例的灵魂service RouteGuide中定义了恰好覆盖四种通信模型的四个方法syntax proto3; package routeguide; service RouteGuide { // 简单 RPCUnary给定位置返回该位置的 Feature rpc GetFeature(Point) returns (Feature) {} // 服务端流式 RPC给定矩形区域流式返回区域内所有 Feature rpc ListFeatures(Rectangle) returns (stream Feature) {} // 客户端流式 RPC持续上报路线上的点结束时返回行程汇总 rpc RecordRoute(stream Point) returns (RouteSummary) {} // 双向流式 RPC一边发送沿途留言一边接收其他用户的留言 rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} } message Point { int32 latitude 1; int32 longitude 2; } message Rectangle { Point lo 1; Point hi 2; } message Feature { string name 1; Point location 2; } message RouteNote { Point location 1; string message 2; } message RouteSummary { int32 point_count 1; int32 feature_count 2; int32 distance 3; int32 elapsed_time 4; }几个值得注意的协议细节坐标采用E7 表示法经纬度乘以 10^7 后取整存储注释明确说明 Latitudes 范围为 ±90 度、Longitudes 为 ±180 度GetFeature在目标位置无命名地物时返回name 为空的Feature这是客户端判断该位置是否有地物的依据ListFeatures选择流式而非repeated字段一次性返回注释解释了原因矩形区域可能覆盖很大范围、包含海量地物RouteSummary汇总了四个统计维度接收点数、经过的已知地物数、累计距离米、耗时秒。3.4 服务端实现回调 API 下的四种 Reactorroute_guide_callback_server.cc 以Callback API回调 API实现了全部四个 RPC服务类继承RouteGuide::CallbackService。与同步版route_guide_server.cc相比回调 API 把每个请求的生命周期封装进一个 Reactor 对象由 gRPC 框架自动调度开发者无需手动管理线程。四个方法各演示了一种 Reactor 模式RPCReactor 类型核心实现思路GetFeatureServerUnaryReactor在构造时立即查表、填充响应并调用Finish(Status::OK)OnDone中delete this释放自身ListFeaturesServerWriteReactorFeatureNextWrite()遍历地物列表命中矩形范围lon/lat 落在 lo/hi 之间就StartWrite遍历完调用Finish结束流RecordRouteServerReadReactorPointStartRead持续接收点OnReadDone中累计点数、地物数、相邻点距离读到流结束ok false时回填RouteSummary并FinishRouteChatServerBidiReactorRouteNote, RouteNote收到一条留言后把与同坐标的历史留言逐一StartWrite回发再把自己这条追加进共享received_notes_向量共享状态用absl::Mutex保护注释特别指出Reactor 可能在线程间跳转不能用栈上局部锁代码中还内置了辅助函数GetDistance基于球面余弦公式2 * atan2(sqrt(a), sqrt(1-a)) * RR6371000 米计算两点距离ConvertToRadians做角度转弧度GetFeatureName按坐标精确匹配地物名。此外服务端还注释了一段使用context-DefaultReactor()的简化版GetFeature实现供读者对比两种写法。3.5 客户端实现回调 API 下的读写 Reactorroute_guide_callback_client.cc 在main中依次执行四个调用输出被分隔成-------------- GetFeature --------------等四个区段GetFeature用stub_-async()-GetFeature(context, point, feature, callback)发起异步一元调用在回调里按失败 / 响应不完整 / 无地物 / 有地物四种情况分别打印回调通过std::mutexstd::condition_variable把结果同步回主线程ListFeaturesClientReadReactorFeature在OnReadDone中逐条打印流式返回的地物OnDone里用条件变量唤醒Await()RecordRouteClientWriteReactorPoint随机挑选 10 个地物作为参观点points_remaining_ 10每次写入后通过grpc::Alarm延迟 500–1500 毫秒再写下一个模拟真实行进节奏全部写完后StartWritesDone()并汇总服务端返回的RouteSummaryRouteChatClientBidiReactorRouteNote, RouteNote预置 4 条留言分布在 3 个坐标一边发送、一边打印接收到的回复实现双向并发通信。客户端同样通过routeguide::ParseDb(db, feature_list_)定义在 helper.cc解析 JSON 数据库。需要说明的是helper 中的Parser是一个按[{location:{latitude:...,longitude:...},name:...}]固定格式手写的简易 JSON 解析器README 级注释也强调它要求数据库文件具备精确格式并非通用 JSON 库——这也是 route_guide_db.json 数据格式必须严格一致的原因。3.6 同步版对照除回调 API 实现外目录下还保留了经典同步版本 route_guide_server.cc 与 route_guide_client.cc。同步版服务端每个 RPC 占用一个工作线程gRPC 内部线程池处理而回调版把并发模型交给框架的 Reactor 调度。两者共享同一份 proto 与 helper适合对照学习 gRPC C 两种编程模型的差异。四、更进一步的示例地图索引文档特意说明目录中其他示例请查看各自的 README这暗示了一套进阶学习路径。例如认证与安全auth/演示 TLS 与 token 认证gcp_observability/演示云环境下的链路观测可靠性deadline/、retry/、wait_for_ready/、keepalive/、flow_control/分别对应超时、重试、就绪等待、保活与流控可观测性otel/集成 OpenTelemetryreflection/提供服务反射health/提供健康检查服务Hello World 服务端中的EnableDefaultHealthCheckService(true)即与此相关生产调度load_balancing/、xds/、csm/、orca/覆盖负载均衡、xDS 控制面与自定义负载报告通信增强metadata/、compression/、interceptors/、cancellation/、error_handling/、error_details/、multiplex/、systemd_socket_activation/、unix_abstract_sockets/、default_event_engine/、generic_api/、debugging/分别从元数据、压缩、拦截器、取消、错误处理、多路复用、系统集成等维度展开。五、在 MongoDB 仓库中使用这些示例的前提与注意事项从仓库结构看gRPC 以third_party 形式整体 vendored于 src/third_party/grpc/dist因此构建路径示例命令tools/bazel run examples/cpp/route_guide:...面向 gRPC 发行版自身布局原文档即如此书写在 MongoDB 仓库根目录下同样存在 tools/bazel 封装脚本若要在本仓库内直接构建这些示例需要先确认相应 Bazel 工作区与//:grpc、//examples/protos:*目标在仓库构建图中的可见性生成代码示例源码通过#ifdef BAZEL_BUILD分支切换examples/protos/*.grpc.pb.h与本地*.grpc.pb.h两种头文件包含方式如 greeter_server.cc这些是构建期由 protoc/grpc_cpp_plugin 生成的代码运行前需完成对应代码生成步骤默认值差异db_path的默认值随构建方式不同而变化Bazel 构建指向examples/cpp/route_guide/route_guide_db.json非 Bazel 构建指向route_guide_db.json切换构建系统时需显式传入--db_path否则会因找不到数据文件而abort()无认证示例Hello World 与 Route Guide 均使用InsecureServerCredentials/InsecureChannelCredentials仅适合本地学习生产环境务必参考auth/与安全相关文档的 TLS 方案。小结这份索引文档虽然只有寥寥数行却精确地勾勒出 gRPC C 学习的完整路径——用 Hello World 完成第一个程序的快速起步用 Route Guide 系统掌握四种 RPC 模型再按需深入 20 余个高级示例。结合仓库内的源码、proto 与 BUILD 定义逐行研读即可快速建立起对 gRPC C 服务端、客户端与回调 API 的完整认知这套知识体系对理解 MongoDB 中任何基于 gRPC 的内部服务如 mongot 集成等同样具有直接借鉴价值。【免费下载链接】mongoThe MongoDB Database项目地址: https://gitcode.com/GitHub_Trending/mo/mongo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表