Tkrzwæ¬ä½ã§ããããäºãããåã£ãã®ã§ããã¼ã¿ãã¼ã¹ãµã¼ãã¹ã§ãä½ã£ã¦ã¿ãããæ¢ã«ã¬ããªãã¼ã¿ãã¼ã¹ãµã¼ãã¹ã¯å±±ã»ã©ããã®ã§ãã¬ãããªã¼ã·ã£ã³ã«æ¢ãã¦é£ã³è¾¼ãã®ãæ°ãå¼ãããã¨ã¯ãããgRPCã使ãã¨ããªãæ°è»½ã«é«æ§è½ãªãµã¼ãã¹ãå®è£ ã§ããã®ã§ãæ¥æ大工ã®ã¤ããã§åãçµãããããã10åãããã®é£è¼ã«ãªãã ãããããããããã°ãããã¼ã¿ãã¼ã¹ãµã¼ãã¹ã®è¨è¨ã¨å®è£ ã«ã¤ãã¦è¿°ã¹ã¦ããããã
ååã¯ãgRPCã®åºæ¬çãªä½¿ãæ¹ã確èªãããã¤ã³ã¹ãã¼ã«æ¹æ³ããã«ãã®èªååãAPIã®å®ç¾©ãå®è£ ãããã¦ãã¹ãã¾ã§ã®ä¸é£ã®æµãã追ãã
ã¾ãæè¡é¸å®ã«ã¤ãã¦ã ããããã¯ããgRPCä¸æãªã®ã ãTokyo TyrantãKyoto Tycoonã§ã¯ãsocketã¨ãselectã¨ãpollã¨ãepollã¨ãkqueueã¨ããã£ãã·ã¹ãã ã³ã¼ã«ãé§ä½¿ãã¦èªåã§RPCæ©è½ãå®è£ ãã¦ããããé¢åãããããã競äºåã®ããæ§è½ã«å°éããã«ã¯ãããªãã®è©¦è¡é¯èª¤ãè¦ããããæ§ã ãªå®è¡ç°å¢ã¸ã®ç§»æ¤æ§ã確ä¿ããã®ã¯æ¬å½ã«å¤§å¤ã ãä»åã¯ããã«å·¥æ°ããããã«ãæ¢åã®ä»çµã¿ã«ä¹ã£ãããããRPCã®ãã¬ã¼ã ã¯ã¼ã¯ã¨ãã¦ã¯ä»ã«ãRESTããSOAPããCORBAããã«åºã¥ããã®ãå±±ã»ã©ããããæ§è½ã¨å©ä¾¿æ§ã¨å¯æ¬æ§ã«ããã¦gRPCãä»ã®ã¨ããæå¼·ã ã¨æãã
gRPCã®è©³ç´°ã«é¢ãã¦ã¯本家のサイトãåç §ããã ãã®ãããã ãããgRPCã¯ãããã¯ã¼ã¯æ©è½ãé è½ãã¦ããããgRPCã使ããªãå ´åãå®è£ ä¾åã®ã·ã¹ãã ã³ã¼ã«ã使ã£ã¦ãããã¯ã¼ã¯ã¨ãã®å¤éåã®æ©è½ãã´ãªã´ãªå®è£ ããªãã¨ãããªãã®ã ããgRPCã¯ãããã£ãæ³¥èãé¨åãé è½ãã¤ã¤ãååã«ç«¶äºåã®ããæ§è½ãæä¾ãã¦ããããã¾ããgRPCã¯ã¡ãã»ã¼ã¸ã®äº¤æã«Protocol Buffersã使ãã®ã§ãæè»ãªAPIãç°¡åã«è¨è¨ããã³å®è£ ãããã¨ãã§ããæ§ã ãªè¨èªãå®è¡ç°å¢ã§å®¹æã«ã¯ã©ã¤ã¢ã³ããå®è£ ã§ãããç¹°ãè¿ãã«ãªãããgRPCããªãã¦ãåçã®ãã¨ã¯ã§ããã®ã ããgRPCã使ãã¨ãã£ã¡ã楽ãªã®ã ã楽ã§ãããã¨ãè¦ç¹ãªã®ã§ã楽ã«å§ããããããã«ã¡ã¢ãæ®ãã¦ããããã
ã¾ãã¯ã¤ã³ã¹ãã¼ã«ã ãæ¬å®¶ã®æé ã ã¨ãGitHubã®ããã¸ã§ã¯ããcloneãã¦cmakeã§ã´ãã§ã´ãã§ããæãã«ãªã£ã¦ããã®ã ããUbuntu Linuxã ã¨ãã®ãããã¯ç°¡ç¥åã§ãããaptã使ã£ã¦ãµã¯ãã¨ã¤ã³ã¹ãã¼ã«ããã°ããã
$ apt-get install libprotobuf-dev libgrpc-dev libgrpc++-dev
å¤åãlibgrpc++-devã ãå ¥ãããã¨ããã°æ®ãã®äºã¤ãèªåçã«ã¤ã³ã¹ãã¼ã«ãããããããã«ãããä¸è¨ãå®è¡ããã¨ãProtocol Buffersã®ã³ã³ãã¤ã©ã¨ããã®gRPCç¨ãã©ã°ã¤ã³ã¨ãgRPCã®ã©ã¤ã³ã¿ã¤ã ã©ã¤ãã©ãªãå ¨ã¦ã¤ã³ã¹ãã¼ã«ãããã
ã¾ãããã«ããèªååããæ¹æ³ã«ã¤ãã¦ã¯æ¨ªã«ç½®ãã¦ãæåã§ãã«ãããæ¹æ³ãå¦ã¶ã¹ãã ãProtocol Buffersã¨æ¯åæ¸ãã®ã¯é·ãã®ã§ã以å¾PBã¨å¼ã¶ãgRPCã§ã¯ãã¤ã³ã¿ã¼ãã§ã¤ã¹ãprotoãã¡ã¤ã«ã§å®ç¾©ãã¦ããã¦ããããC++çã®ã½ã¼ã¹ã³ã¼ãã«å¤æãããC++ã®å ´åãprotoãã¡ã¤ã«ãã2種é¡ã®ã½ã¼ã¹ãã¡ã¤ã«ãåºåãããã²ã¨ã¤ã¯é常ã®PBã¡ãã»ã¼ã¸ãå®è£ ããã®ããã®ãã®ã§ãããã²ã¨ã¤ã¯gRPCã®ãµã¼ãã¹ãå®è£ ããããã®ãã®ã ãå¾è ã¯protocã«gRPCç¨ã®ãã©ã°ã¤ã³grpc_cpp_pluginã渡ãã¦çæãããä¾ãã°tkrzw_rpc.protoãã両è ãçæããã«ã¯ã以ä¸ã®ãããªã³ãã³ããå®è¡ããã
protoc -I . --cpp_out=. tkrzw_rpc.proto protoc -I . --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin tkrzw_rpc.proto
çµæã¨ãã¦ãtkrzw_rpc.pb.hãtkrzw_rpc.pb.hãtkrzw_rpc.pb.ccãtkrzw_rpc.grpc.pb.hãtkrzw_rpc.grpc.pb.ccãçæãããããã¨ã¯ãèªåã®ããã¸ã§ã¯ãã®ä¸ã§ããããçµã¿è¾¼ãã C++ã®ã³ã¼ããæ¸ãã°ããããµã¼ãå´ã®ããã°ã©ã ã§ãã¯ã©ã¤ã¢ã³ãå´ã®ããã°ã©ã ã§ããtkrzw_rpc.pb.oã¨tkrzw_rpc.grpc.pb.oã®ä¸¡è ããªã³ã¯ããã¨ã¨ãã«ãgRPCå ±éã®ã©ã³ã¿ã¤ã ã¨ããªã³ã¯ããå¿ è¦ããããããªãã¡ããµã¼ãã¨ã¯ã©ã¤ã¢ã³ãã¯ä»¥ä¸ã®ãããªã³ãã³ãã§ãã«ãã§ãããã¨ã«ãªãã
$ g++ -I. -o server server.cc tkrzw_rpc.pb.cc tkrzw_rpc.grpc.pb.cc \ -lgrpc++_reflection -lgrpc++ -lgrpc -lprotobuf $ g++ -I. -o client client.cc tkrzw_rpc.pb.cc tkrzw_rpc.grpc.pb.cc \ -lgrpc++_reflection -lgrpc++ -lgrpc -lprotobuf
å®éã«ã¯ãã½ã¼ã¹ããç´ã§å®è¡å¯è½ãã¤ããªãä½ãã®ã§ã¯ãªãããªãã¸ã§ã¯ããã¡ã¤ã«ãä½ã£ã¦ããããã¾ã¨ããã©ã¤ãã©ãªãä½ã£ã¦ãããããªã³ã¯ãã¦å®è¡å¯è½ãã¤ããªãä½ãã¨ããæé ã«ãªãããããèªååããããæ¬å®¶ãæ¨ãæ¨ãã®cmakeã使ã£ã¦ã¢ããªã±ã¼ã·ã§ã³ããã«ãããã®ãããããããã¯æ¢ãã¦å¤ãè¯ãconfigureã¨Makefileã®çµã¿åããã§ãã£ã¦ã¿ããã
説æã®ããã«ããã®ãããåç´åããMakefileãæ¸ããªãã以ä¸ã®ããã«ã§ããã
# ãã«ãã¿ã¼ã²ãã all : tkrzw_server tkrzw_client # protoããC++ã½ã¼ã¹ãä½ã tkrzw_rpc.pb.h tkrzw_rpc.pb.cc : tkrzw_rpc.proto protoc -I . --cpp_out=. tkrzw_rpc.proto tkrzw_rpc.grpc.pb.h tkrzw_rpc.grpc.pb.cc : tkrzw_rpc.proto protoc -I . --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin tkrzw_rpc.proto # C++ã½ã¼ã¹ãããªãã¸ã§ã¯ããã¡ã¤ã«ãä½ã .SUFFIXES : .SUFFIXES : .cc .o .cc.o : g++ -c -I . -O2 $< tkrzw_rpc.o : tkrzw_rpc.pb.h tkrzw_rpc.grpc.pb.h tkrzw_server.o : tkrzw_server_impl.h # ãªãã¸ã§ã¯ããã¡ã¤ã«ããã©ã¤ãã©ãªãä½ã libtkrzw_rpc.a : tkrzw_rpc.o tkrzw_rpc.pb.o tkrzw_rpc.grpc.pb.o ar rv $@ $^ # ã¯ã©ã¤ã¢ã³ãã¨ãµã¼ãã®å®è¡å¯è½ãã¤ããªãä½ãã tkrzw_server : tkrzw_server.o libtkrzw_rpc.a g++ -I . -O2 -o $@ $< -L . -ltkrzw_rpc \ -lgrpc++_reflection -lgrpc++ -lgrpc -lprotobuf -ltkrzw \ -lstdc++ -lrt -lpthread -lm -lc tkrzw_client : tkrzw_client.o libtkrzw_rpc.a g++ -I . -O2 -o $@ $< -L . -ltkrzw_rpc \ -lgrpc++_reflection -lgrpc++ -lgrpc -lprotobuf -ltkrzw \ -lstdc++ -lrt -lpthread -lm -lc
å®éã®è¨å®ã¯configure.inã¨Makefile.inãèªãã§ãããã®ãè¯ãã ããã
ãã«ãæ¹æ³ãããã£ãã¨ããã§ãå®éã®å®è£ ä½æ¥ã«å ¥ã£ã¦ããããããªãããããã®æ©è½ãä½ãè¾¼ãã¨å¤§å¤ãªã®ã§ãã¾ãã¯ãµã¼ãã«éã£ãæååããã®ã¾ã¾éãè¿ãã¨ããåç´ãªAPIã ããå®è£ ããããããã¯ãµã¼ãã®çå確èªã«ã使ãããtkrzw_service.protoã«ä»¥ä¸ã®ãããªå 容ãæ¸ãã
syntax = "proto3"; package tkrzw; message EchoRequest { string message = 1; } message EchoResponse { string echo = 1; } service DBMService { rpc Echo(EchoRequest) returns (EchoResponse); }
DBMServiceã¨ããååã®ãµã¼ãã¹ã«ãEchoã¨ããã¡ã½ãããå®ç¾©ããã¦ãããããã¯å ¥åã¨ãã¦EchoRequestã¨ããPBã¡ãã»ã¼ã¸ãåãåããåºåã¨ãã¦EchoResponseã¨ããPBã¡ãã»ã¼ã¸ãè¿ããEchoRequestã¯ä»»æã®æååãå ¥ããããmessageã¨ãããã£ã¼ã«ããæã¡ãEchoResponseã¯åãå 容ã®æååãå ¥ããããechoã¨ãããã£ã¼ã«ãã ããæã¤ã
ãµã¼ãã®å®è¡å¯è½ãã¤ããªãå®è£ ããããtkrzw_server_impl.hã¨ãããã¡ã¤ã«ã ãã¾ãã以ä¸ã®ããããincludeããã
#include <grpc/grpc.h> #include <grpcpp/security/server_credentials.h> #include <grpcpp/server.h> #include <grpcpp/server_builder.h> #include <grpcpp/server_context.h> #include "tkrzw_rpc.pb.h" #include "tkrzw_rpc.grpc.pb.h"
tkrzw_rpc.pb.hãincludeããã¨ãEchoRequestã¨EchoResponseã使ããããã«ãªããtkrzw_rpc.grpc.pb.hãincludeããã¨ãtkrzw::DBMService::Serviceã¨ããæ½è±¡ã¯ã©ã¹ã使ããããã«ãªããããã®ä»®æ³é¢æ°ããªã¼ãã¼ã©ã¤ããã¦ããã¨ãå®éã®æåãå®ç¾©ã§ãããã¨ã«ãªãã
class DBMServiceImpl : public DBMService::Service { public: grpc::Status Echo(grpc::ServerContext* context, const tkrzw::EchoRequest* request, tkrzw::EchoResponse* response) override { response->set_echo(request->message()); return grpc::Status::OK; } };
ãã¨ã¯ãtkrzw_server.ccã«ãµã¼ãã¹ãèµ·åããå¦çãæ¸ãã°ãããã¢ãã¬ã¹ã0.0.0.0ã«ããã¨ããã¼ã«ã«ãã¹ãã®ä»»æã®ãããã¯ã¼ã¯ã¤ã³ã¿ã¼ãã§ã¤ã¹ã«ãã¤ã³ããããããã¼ãçªå·ã¯ç©ºãã¦ããããªãã®ãé©å½ã«è¨å®ãããã¾ããèµ·åãããµã¼ããåæ¢ã·ã°ãã«ãåãåã£ããåæ¢ããããã«ã³ã¼ã«ããã¯ãä»æãããã·ã°ãã«ãã³ãã©ã¯è¤æ°åæã«å®è¡ãããå¯è½æ§ãããã®ã§ãã¢ãããã¯å¤æ°ã§æä»å¶å¾¡ãè¡ã£ã¦ããã
// ã·ã°ãã«ãã³ãã©ã¨ãã¦ããµã¼ããåæ¢ããã std::atomic<grpc::Server*> g_server = nullptr; void ShutdownServer(int signum) { grpc::Server* server = g_server.load(); if (server != nullptr && g_server.compare_exchange_strong(server, nullptr)) { PrintL("Shutting down"); const auto deadline = std::chrono::system_clock::now() + std::chrono::seconds(10); server->Shutdown(deadline); } } // ãµã¼ããå®è¡ãã void RunServer() { const std::string server_address("0.0.0.0:1978"); DBMServiceImpl service; grpc::ServerBuilder builder; builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); builder.RegisterService(&service); std::unique_ptr<grpc::Server> server(builder.BuildAndStart()); PrintL("Listening on ", server_address); g_server = server.get(); std::signal(SIGINT, ShutdownServer); std::signal(SIGTERM, ShutdownServer); std::signal(SIGQUIT, ShutdownServer); server->Wait(); PrintL("Done"); }
ãµã¼ãã®å®è£ ã¯æ®é1ã¤ã§ååãªã®ã§ãå¿ ãããã©ã¤ãã©ãªåããªãã¦ãããããã ãããã¹ãã®ããã«tkrzw_server.ccã¨tkrzw_server_impl.hã®åå²ã¯ãã¦ãããä¸æ¹ã§ãã¯ã©ã¤ã¢ã³ãå´ã®å¦çã¯åå©ç¨ããã®ãæ®éãªã®ã§ãã©ã¤ãã©ãªã«ããæ¹ãè¯ããtkrzw_dbm_remote.hã¨ãããããã§APIãå®ç¾©ãããã
class RemoteDBMImpl; class RemoteDBM final { public: RemoteDBM(); ~RemoteDBM(); // ãµã¼ãã¨æ¥ç¶ãã Status Connect(const std::string& host, int32_t port); // æ¥ç¶ãåæãã void Disconnect(); // ã¡ãã»ã¼ã¸ã®ã¨ã³ã¼ããã¯ãè¡ã Status Echo(std::string_view message, std::string* echo); private: // å®è£ ã®ãã¤ã³ã¿ RemoteDBMImpl* impl_; };
ã¯ã©ã¤ã¢ã³ãå´ã§ã¯ãä¸ã§gRPCã使ããã¦ãããã¨ãå®å ¨ã«é è½ããããC++ã«ããã¦å®è£ ã®å®å ¨é è½ãéæããã«ã¯Pimplã¤ãã£ãªã ã使ããããªããã¯ã©ã¹ã®ã¡ã³ãå¤æ°ã«å®è£ ã¯ã©ã¹ã®ãã¤ã³ã¿ã ããæããããã¨ã«ãããgRPCãPBã®ã·ã³ãã«ããããã«ä¸åç»å ´ããªãããã«ã§ããã®ã ã
å½ç¶ãå®è£ ã¯tkrzw_dbm_remote.ccã§è¡ããã¾ãã以ä¸ã®ããããincludeããã
#include <grpc/grpc.h> #include <grpcpp/channel.h> #include <grpcpp/client_context.h> #include <grpcpp/create_channel.h> #include <grpcpp/security/credentials.h> #include "tkrzw_rpc.h" #include "tkrzw_rpc.grpc.pb.h" #include "tkrzw_rpc.pb.h"
å®è£ ã¯ã©ã¹ã¯ä»¥ä¸ã®ããã«æ¸ããã¨ã«ãªãã
class RemoteDBMImpl final { public: Status Connect(const std::string& host, int32_t port); void Disconnect(); Status Echo(std::string_view message, std::string* echo); private: std::unique_ptr<DBMService::StubInterface> stub_; }; // ãµã¼ãã«æ¥ç¶ãã Status RemoteDBMImpl::Connect(const std::string& host, int32_t port) { // ãã¹ãåã¨ãã¼ãçªå·ãé£çµãã¦ã¢ãã¬ã¹æååãä½ã const std::string server_address(StrCat(host, ":", port)); // ãã£ã³ãã«ãä½ã auto channel = grpc::CreateChannel(server_address, grpc::InsecureChannelCredentials()); // æ¥ç¶ã§ããã¾ã§å¾ 㤠const auto deadline = std::chrono::system_clock::now() + std::chrono::seconds(10); while (true) { auto status = channel->GetState(true); if (status == GRPC_CHANNEL_READY) { break; } if ((status != GRPC_CHANNEL_IDLE && status != GRPC_CHANNEL_CONNECTING) || !channel->WaitForStateChange(status, deadline)) { return Status(Status::NETWORK_ERROR, "connection failed"); } } // ã¹ã¿ããä½ãã stub_ = DBMService::NewStub(channel); return Status(Status::SUCCESS); } // æ¥ç¶ãåæãã void RemoteDBMImpl::Disconnect() { // ã¹ã¿ããç ´æ£ããããã¹ãã©ã¯ã¿ã§æ¥ç¶ãåæãããã stub_.reset(nullptr); } // ã¨ã³ã¼ããã¯ãè¡ã Status RemoteDBMImpl::Echo(std::string_view message, std::string* echo) { // ã³ã³ããã¹ãã¨å ¥åºåãæºå grpc::ClientContext context; EchoRequest request; request.set_message(std::string(message)); EchoResponse response; // RPCãåæçã«å¼ã¶ grpc::Status status = stub_->Echo(&context, request, &response); // ã¹ãã¼ã¿ã¹ã®ç¢ºèª if (!status.ok()) { return Status(Status::NETWORK_ERROR, GRPCStatusString(status)); } // çµæã®åãåºã *echo = response.echo(); return Status(Status::SUCCESS); }
gRPCã®æä½ã®æå¦ã¯grpc::Statusã¨ããæ§é ä½ã§è¿ãããã®ã ããããã§ã¯ãããtkrzw::Statusã«å¤æãã¦ãããgRPCã®ã·ã³ãã«ã¯ä¸åå¤ã«åºããªãããªã·ã¼ãªã®ã ã
ãã¨ã¯ãä¸è¨ã®ã©ã¤ãã©ãªãå©ç¨ããã¯ã©ã¤ã¢ã³ãã®å®è¡å¯è½ãã¤ããªãæ¸ãã°è¯ããtkrzw_dbm_remote_util.ccã¨ãããã¡ã¤ã«ã ã
void run() { RemoteDBM dbm; dbm.Connect("localhost", 1978); std::string echo; status = dbm.Echo("hello", &echo); std::cout << echo << std::endl; }
ãµã¼ãã¨ã¯ã©ã¤ã¢ã³ããèµ·åããã«ã¯ãããããå¥ã¿ã¼ããã«ã§ä»¥ä¸ã®ããã«ããã°ããã
$ tkrzw_server
$ tkrzw_dbm_util echo hello hello
gTestã§ã¦ããããã¹ããæ¸ããå½ç¶ãªãããã¦ãããæ¯ã«ãããªãã¡ãµã¼ãã¨ã¯ã©ã¤ã¢ã³ãã§å¥ã
ã«ããã¹ããæ¸ããªããã°ãªããªããã¾ãã¯ãµã¼ãå´ã ããtkrzw_server_test.ccã¨ãããã¡ã¤ã«ã«å®ç¾©ãããDBMServiceImplã¯ã©ã¹ã®ã¡ã½ããããã®ã¾ã¾å¼ã¹ãã®ã§æ¯è¼ç楽ã«æ¸ããã
TEST_F(ServerTest, Basic) { tkrzw::DBMServiceImpl server; grpc::ServerContext context; tkrzw::EchoRequest request; request.set_message("hello"); tkrzw::EchoResponse response; grpc::Status status = server.Echo(&context, &request, &response); EXPECT_TRUE(status.ok()); EXPECT_EQ("hello", response.echo()); }
次ã«ã¯ã©ã¤ã¢ã³ãå´ã ãããã¡ãã¯gMockã使ããgRPCã®ããããæ¸ãåºãprotocã³ãã³ããæ¸ãæãã¦ãã¹ã¿ãã®ã¢ãã¯ã¯ã©ã¹ãèªåçæããããåºåå½¢å¼ã "." ãã "generate_mock_code=true:." ã«å¤ããã°ããã
protoc -I . --grpc_out=generate_mock_code=true:. --plugin=protoc-gen-grpc=grpc_cpp_plugin tkrzw_rpc.proto
ããããã¨ãtkrzw_rpc_mock.grpc.pb.hãçæãããããã¨ã¯ãããã使ã£ããã¹ããtkrzw_dbm_remote_test.ccã¨ãããã¡ã¤ã«ã«å®ç¾©ããã
TEST_F(RemoteDBMTest, Basic) { // ãã¹ãã¹ã¿ããå®ç¾©ãã¦ãããã«æå¾ ãããã¢ã¯ã»ã¹ãã¿ã¼ã³ãè¨è¿°ããã auto stub = std::make_unique<tkrzw::MockDBMServiceStub>(); tkrzw::EchoResponse response; response.set_echo("hello"); EXPECT_CALL(*stub, Echo(_, _, _)).WillOnce( DoAll(SetArgPointee<2>(response), Return(grpc::Status::OK))); // ã¯ã©ã¤ã¢ã³ããä½ã£ã¦ããã¹ãã¹ã¿ãã渡ãã tkrzw::RemoteDBM dbm; client.InjectStub(stub.release()); // ã¡ã½ãããå¼ã³åºãã¦ãçµæãæ¤æ»ããã std::string echo; const tkrzw::Status status = dbm.Echo("hello", &echo); EXPECT_EQ(tkrzw::Status::SUCCESS, status); EXPECT_EQ("hello", echo); }
ãã¹ãã¹ã¿ããæ³¨å ¥ããããã«InjectStubã¨ããã¡ã½ããã追å ããã¦ãããæ£ç´ããã¯ããµãã³ã¼ãã ãããã¯gRPCãé è½ãããã¨ã®å¯ä½ç¨ã¨ãè¨ãããä»äºã§ããã°ãã¢ããªã±ã¼ã·ã§ã³å´ã®è²¬ä»»ã§ã¹ã¿ããä½ã£ã¦ãµã¼ãã«æ¥ç¶ããä¸ã§ãRemoteDBMã¯ã©ã¹ã®ã³ã³ã¹ãã©ã¯ã¿ã«ãã®ã¹ã¿ãã渡ããããªã¤ã³ã¿ã¼ãã§ã¤ã¹ã«ããã ãããå©ç¨è ãgRPCã«ç²¾éãã¦ãããã¨ãæå¾ ã§ããã®ã§ãé è½ããå¿ è¦ããªãããã ãããããããã§ã¯ãgRPCãã¹ã¿ãã®åå¨ãé è½ãã¦ãConnectã¡ã½ãããæ¥ç¶ãæ ãããã«ãããããããã¨ãã¹ãã¹ã¿ãã渡ããªããªã£ã¦ãã¾ãã®ã§ãä»æ¹ãªãInjectStubã¨ããã¡ã½ãããå¿ è¦ã«ãªã£ãã¨ããããã ã
ã¾ã¨ãããã¼ã¿ãã¼ã¹ã©ã¤ãã©ãªTkrzwã®å種æ©è½ããµã¼ãã¹ã¨ãã¦å©ç¨ã§ããããã«ãã¹ããgRPCã使ã£ã¦ãµã¼ãã¹ã®éå½¢ãå®è£ ãããæ £ããªããã©ãããã©ã¼ã ã使ãå ´åãMakefileã®æ§é ã決ããã®ãæãé¢åã ã£ããããã®ã ããä»åã§ãããããªãããããã¾ã§ã®ç¥èããããã°ãããåã£ããåç¶ã ãprotoãã¡ã¤ã«ã«APIã追å ãã¦ããã®å®è£ ãtkrzw_server.ccã«å®ç¾©ãã¦ããããå¼ã³åºãã³ã¼ããtkrzw_rpc.hã¨tkrzw_rpc.ccã«å®ç¾©ããã°ããã次å以éã¯å ·ä½çãªAPIãå®ç¾©ãã¦ãå®ç¨çãªããã°ã©ã ã«å°ããã¤è¿ã¥ãã¦ããã