如何将现有C++有状态交互式后端封装为gRPC服务
问题解答
1. Context变量的初始化与销毁
你的Context是跨请求保留状态的全局上下文,直接作为BarServiceImpl的成员变量即可:
- 初始化:放在
BarServiceImpl的构造函数中调用setUpContext完成,服务启动、实例化BarServiceImpl的时候就会执行,只会初始化一次 - 销毁:放在
BarServiceImpl的析构函数中执行对应销毁逻辑,服务停止、Service实例销毁时自动触发
注意:同步gRPC服务默认多线程处理请求,如果你的Context结构不支持多线程并发读写,需要在成员变量里加锁,处理请求时先加锁再操作Context,避免并发冲突。
2. 用户输入传递给backend逻辑
把原backend.cc里的命令处理逻辑封装成独立的可调用函数,剥离原有的标准输入输出依赖:
原逻辑里从std::cin读输入的部分改成从函数入参取用户命令,原std::cout输出结果的部分改成通过函数返回值/输出参数返回结果,比如封装成签名为std::string process_cmd(Context& ctx, const std::string& user_cmd)的函数。
在gRPC的doSomething接口中,拿到request->question()的用户输入后,直接调用这个封装好的函数,把成员变量的Context和用户输入传入即可。
3. 执行结果返回用户
封装好的处理函数返回的结果,直接赋值给返回参数reply的answer字段即可,gRPC框架会自动把序列化后的结果返回给调用端。
修正后的完整代码示例
第一步:封装backend逻辑
把原backend.cc的逻辑拆分出独立的头文件和实现,比如:
// backend.h #include <string> // 你原来的Context结构定义放在这 struct Context {}; void setUpContext(Context& ctx); void destroyContext(Context& ctx); std::string process_cmd(Context& ctx, const std::string& cmd);
// backend.cc #include "backend.h" #include <iostream> void setUpContext(Context& ctx) { // 你原来的初始化逻辑 } void destroyContext(Context& ctx) { // 你原来的销毁逻辑,原来没写的话现在补上 } std::string process_cmd(Context& ctx, const std::string& cmd) { // 你原来的处理逻辑,这里简化示例 if (cmd == "STOP") { // 这里可以加触发gRPC服务停止的逻辑,按需实现 return "Service will stop"; } return "Hey!"; }
第二步:修改server.cc
#include <iostream> #include <memory> #include <string> #include <mutex> #include <grpc++/grpc++.h> #include "foo.grpc.pb.h" #include "backend.h" using grpc::Server; using grpc::ServerBuilder; using grpc::ServerContext; using grpc::Status; using foo::BasicRequest; using foo::BasicResponse; using foo::Bar; class BarServiceImpl final : public Bar::Service { public: BarServiceImpl() { setUpContext(_context); } ~BarServiceImpl() override { destroyContext(_context); } Status doSomething(ServerContext * context, const BasicRequest * request, BasicResponse * reply) override { std::lock_guard<std::mutex> lock(_ctx_mutex); // Context线程安全的话可以去掉这行 std::string cmd = request->question(); std::string res = process_cmd(_context, cmd); reply->set_answer(res); return Status::OK; } private: Context _context; std::mutex _ctx_mutex; }; void RunServer() { std::string server_address("0.0.0.0:4321"); BarServiceImpl service; ServerBuilder builder; builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); builder.RegisterService(&service); std::unique_ptr<Server> server(builder.BuildAndStart()); std::cout << "Server listening on " << server_address << std::endl; server->Wait(); } int main(int argc, char ** argv) { RunServer(); return 0; }
注:以上代码已经修正你原始server.cc里的笔误,包括错误的返回参数类型OneValueReply、错误的服务实例类型ArithmeticsServiceImpl、指针调用语法错误等问题。
内容的提问来源于stack exchange,提问作者Homunculus Reticulli
相关产品推荐
相关产品推荐

