ãªã¢ãŒãããã·ãŒãžã£ã³ãŒã«ã®å Žåãç©äºã¯ããç¥ãããŠããã³ããã¯ã14 StandardsããšãŸã£ããåãã§ãããå€ä»£DCOMãšCorbaãå¥åŠãªSOAPãš.NET RemotingãçŸä»£ã®RESTãšAMQPïŒã¯ããç¥ã£ãŠããŸãïŒ -ããã¯æ£åŒã«ã¯RPCã§ã¯ãããŸãããçšèªã説æããããã«ãæè¿ç¹å¥ãªãããã¯ãäœæããŸããããããã§ããã¹ãŠRPCãšããŠäœ¿çšãããäœããã¢ãã«ã®ããã«èŠããã¢ãã«ã®ããã«æµ®ãã¶å Žåã¯- ããããŸã ïŒ ã
ãããŠãã¡ãããã³ããã¯ããã¯ã®ã·ããªãªã«å®å šã«æºæ ããŠãGoogleã¯åžå Žã«åå ¥ããæçµçã«æãæ£ç¢ºãªæåŸã®RPCæšæºãäœæããããšãçºè¡šããŸããã Googleã¯ç解ã§ããŸã-21äžçŽã«ãã¿ãã€ãã®ããŒã¿ãå€ããŠéå¹ççãªHTTP + RESTã§é§åãç¶ãããšããã¹ãŠã®ãã€ãã§ãéã倱ãã®ã¯ã°ãããŠããŸãã åæã«ãä»ã®èª°ãã®æšæºãæ¡çšããŠãããã以äžè¯ããã®ãæãä»ããªãã£ãããšèšãã®ã¯ã圌ãã®ã¹ã¿ã€ã«ã§ã¯ãŸã£ãããããŸããã
ãããã£ãŠããgRPCãªã¢ãŒãããã·ãŒãžã£ã³ãŒã«ãã®ç¥ã§ããgRPCãæºãããŸããããã¯ãGoogleããã®ãªã¢ãŒãããã·ãŒãžã£ã³ãŒã«ã®æ°ãããã¬ãŒã ã¯ãŒã¯ã§ãã ãã®èšäºã§ã¯ã以åã®ã14æšæºããšã¯ç°ãªããäžçïŒãŸãã¯å°ãªããšããã®äžéšïŒããã£ããã£ããWindows + Visual Studioã§gRPCãã«ããæ§ç¯ããããšããçç±ã«ã€ããŠèª¬æããŸãæ瀺ã¯å¿ èŠãªãããš-å ¬åŒææžã«ã¯5ã€ã®éèŠãªã¹ãããããããŸãããããããªãã§ã¯äœãèµ·ãããŸããïŒããŸãããªã¯ãšã¹ããšåçã亀æããç°¡åãªãµãŒãã¹ãšã¯ã©ã€ã¢ã³ããäœæããŠã¿ãŠãã ããã
ãªãå¥ã®èŠæ Œãå¿ èŠãªã®ã§ããïŒ
ãŸããåšããèŠãŠã¿ãŸãããã äœãèŠããŸããïŒ REST + HTTP / 1.1ã衚瀺ãããŸãã ãããããã¹ãŠããããŸãããã¯ã©ã€ã¢ã³ããšãµãŒããŒéã®éä¿¡ã®å€§ç©ºã®4åã®3ãéããã®ã¯ãã®ã¯ã©ãŠãã§ãã ããèŠããšãRESTã¯95ïŒ ã®ã±ãŒã¹ã§CRUDã«çž®éããŠããããšãããããŸãã
ãã®çµæã次ã®ããšãã§ããŸãã
- HTTP / 1.1ãããã³ã«ã®éå¹ç-éå§çž®ããããŒãå®å šãªåæ¹åéä¿¡ã®æ¬ åŠãOSãªãœãŒã¹ã®äœ¿çšã«å¯Ÿããéå¹ççãªã¢ãããŒããäœåãªãã©ãã£ãã¯ãäœåãªé 延ã
- ããŒã¿ãšã€ãã³ãã¢ãã«ãREST + CRUDã§ååŸããå¿ èŠããããŸããããã¯ããã°ãã°å°çäžã®é¢šè¹ã®ããã«ãªããYandexã«ãééããªãéåžžã«è¯ãèšäºãæžãããšã匷å¶ããŸãããšã¬ã¡ã³ã¿ã«-PUTãŸãã¯POSTãå¬åããåªæãå±ããã®ã¯ãªãã§ããïŒ ãããŠãã©ã®çš®é¡ã®HTTPã³ãŒããè¿ãã®ããšãããšãã3ã»ã«é²ãã§æ°ããã«ãŒããåŒãããšããæå³ã§ãã
ãããgRPCã®å§ãŸãã§ãã ç®±ããåºããŠããã«ïŒ
- ããŒã¿åãšã·ãªã¢ã«åãèšè¿°ããããã®ããŒã«ãšããŠã®Protobuf ã å®éã«ã¯éåžžã«ã¯ãŒã«ã§å®èšŒæžã¿ã®ãã®ã å®éåé¡ãšããŠãããã©ãŒãã³ã¹ãå¿ èŠãªäººã¯ãProtobufãæçšããåã«ã茞éãå¥ã«æ°ã«ããŸãã ããã§ãã¹ãŠãå®äºããŸããã
- ãã©ã³ã¹ããŒããšããŠã®HTTP / 2ã ãããŠãããã¯éåžžã«åŒ·åãªåãã§ãïŒ å®å šãªããŒã¿å§çž®ããã©ãã£ãã¯å¶åŸ¡ããµãŒããŒããã®ã€ãã³ãã®ããªã¬ãŒãè€æ°ã®äžŠåãªã¯ãšã¹ãã«1ã€ã®ãœã±ãããåå©çšããããšã®é åã¯ãã°ããããã®ã§ãã
- éçãã¹-ããµãŒãã¹/ã³ã¬ã¯ã·ã§ã³/ãªãœãŒã¹/ãªã¯ãšã¹ããã¯ãããããŸãããïŒ ãã©ã¡ãŒã¿ãŒ=å€ãã ããã§ãããµãŒãã¹ããšãã®äžèº«ã ãããã¢ãã«ãšãã®ã€ãã³ãã®èŠ³ç¹ãã説æãããŸãã
- ã¡ãœãããHTTPã¡ãœããã«ãã€ã³ããããæ»ãå€ãHTTPã¹ããŒã¿ã¹ã«ãã€ã³ãããŸããã 欲ãããã®ãæžããŠãã ããã
- SSL / TLSãOAuth 2.0ãGoogleãµãŒãã¹ãä»ããèªèšŒãããã³ç¬èªã®ïŒããšãã°ã2èŠçŽ ïŒ
- 9èšèªã®ãµããŒãïŒCãC ++ãJavaãGoãNode.jsãPythonãRubyãObjective-CãPHPãCïŒãã©ã¹ããã¡ãããå°ãªããšãBrainfacã§ããŒãžã§ã³ãååŸããŠå®è£ ããããšãçŠæ¢ãã人ã¯ããŸããã
- Googleã®å ¬éAPIã§ã®gRPCã®ãµããŒãã ãã§ã«äžéšã®ãµãŒãã¹ã§æ©èœããŠããŸã ã ããããRESTããŒãžã§ã³ã¯ãã¡ããæ®ããŸãã ããããéžæè¢ãããå Žåã¯èªåã§å€æããŠãã ãã-ããšãã°ãã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ã®RESTããŒãžã§ã³ã䜿çšããŠã1ç§ã§ããŒã¿ãæäŸããããåãéçºã³ã¹ãã§0.5ç§åäœããgRPCããŒãžã§ã³ã䜿çšããŸã-äœãéžæããŸããïŒ ãããŠãããªãã®ç«¶äºçžæã¯äœãéžã³ãŸããïŒ
GRPCã¢ã»ã³ããª
å¿ èŠãªãã®ïŒ
- Git
- Visual Studio 2013 + Nuget
- CMake
ã³ãŒããåãåããŸã
- GithubããgRPCãªããžããªãååŸããŸã
- ã³ãã³ããå®è¡ãã
git submodule update --init
-ããã¯ãäŸåé¢ä¿ïŒprotobufãopensslãªã©ïŒãããŠã³ããŒãããããã«å¿ èŠã§ãã
ProtobufããŸãšãã
- grpc \ third_party \ protobuf \ cmakeãã©ã«ããŒã«ç§»åããããã«ãã«ããã©ã«ããŒãäœæããŸãã
- ã³ãã³ããå®è¡ãã
cmake -G "Visual Studio 12 2013" -DBUILD_TESTING = OFF ... - Visual Studioã§åã®æé ã§äœæããprotobuf.slnãã¡ã€ã«ãéããã¢ã»ã³ãã«ããŸãïŒF7ïŒã
ãã®æ®µéã§ã貎éãªã¢ãŒãã£ãã¡ã¯ã-protoc.exeãŠãŒãã£ãªãã£ãååŸããŸããããã¯ãgRPCããªã³ã¯ãããšãã«å¿ èŠãªããŒã¿ãšlibãã¡ã€ã«ã®ã·ãªã¢ã«å/éã·ãªã¢ã«åã³ãŒããçæããããã«å¿ èŠã§ãã - grpc \ third_party \ protobuf \ cmake \ build \ Debugãã©ã«ããŒãgrpc \ third_party \ protobuf \ cmakeãã©ã«ããŒã«ã³ããŒããŸãã
ããäžåºŠ-Debugãã©ã«ããŒã1ã¬ãã«äžã«ã³ããŒããå¿ èŠããããŸãã ããã¯ãgRPCãšProtobufã®ããã¥ã¡ã³ãã«ããçš®ã®ççŸã§ãã Protobufã¯ããã«ããã©ã«ããŒã§ãã¹ãŠããã«ãããå¿ èŠããããšèšã£ãŠããŸãããgRPCãããžã§ã¯ãã®ãœãŒã¹ã¯ãã®ãã©ã«ããŒã«ã€ããŠäœãç¥ãããgrpc \ third_party \ protobuf \ cmake \ Debugã§çŽæ¥Protobufã©ã€ãã©ãªãæ¢ããŸã
gRPCãæ§ç¯ãã
- ãã¡ã€ã«grpc \ vsprojects \ grpc_protoc_plugins.slnãéããŠåéããŸãã
åã®æé ã§Protobufãã«ããæ£ããå®äºããå Žåããã¹ãŠãã¹ã ãŒãºã«é²ã¿ãŸãã ããã§protoc.exeã®ãã©ã°ã€ã³ããããã·ãªã¢ã«å/éã·ãªã¢ã«åã³ãŒããçæã§ããã ãã§ãªããgRPCæ©èœãè¿œå ã§ããŸãïŒå®éã«ã¯ããªã¢ãŒãããã·ãŒãžã£ã³ãŒã«ïŒã ãã©ã°ã€ã³ãšprotoc.exeã¯ãgrpc \ vsprojects \ Debugãªã©ã®1ã€ã®ãã©ã«ããŒã«é 眮ããå¿ èŠããããŸãã - ãã¡ã€ã«grpc \ vsprojects \ grpc.slnãéããŠåéããŸãã
ã¢ã»ã³ããªã®éçšã§ãNugetã¯å¿ èŠãªäŸåé¢ä¿ïŒopensslãzlibïŒãéå§ããŠããŠã³ããŒãããå¿ èŠããããŸãã Nugetããªãå ŽåããŸãã¯äœããã®çç±ã§äŸåé¢ä¿ãããŠã³ããŒãããªãã£ãå Žåãåé¡ãçºçããŸãã
ãã«ãã®æåŸã«ãgRPCãä»ããéä¿¡ã®ããã«ãããžã§ã¯ãã§äœ¿çšã§ãããã¹ãŠã®å¿ èŠãªã©ã€ãã©ãªãçšæãããŸãã
ç§ãã¡ã®ãããžã§ã¯ã
gRPCã䜿çšããŠHabrahabrçšã®ãã®ãããªAPIãäœæããŸããã
次ã®ã¡ãœããããããŸãã
- GetKarmaã¯ããŠãŒã¶ãŒåãå«ãæååãåãåãããã®ã«ã«ãã®å€ãå«ãå°æ°ãè¿ããŸã
- PostArticleã¯ããã¹ãŠã®ã¡ã¿ããŒã¿ãå«ãæ°ããèšäºãäœæãããªã¯ãšã¹ããåä¿¡ããå ¬éçµæïŒèšäºãžã®ãªã³ã¯ãå ¬éæå»ãå ¬éã倱æããå Žåã®ãšã©ãŒããã¹ããå«ãæ§é ïŒãè¿ããŸãã
ããã¯ãã¹ãŠãgRPCã®èŠ³ç¹ãã説æããå¿ èŠããããŸãã 次ã®ããã«ãªããŸãïŒã¿ã€ãã®èª¬æã«ã€ããŠã¯ã protobufã®ããã¥ã¡ã³ããåç §ããŠãã ããïŒã
syntax = "proto3"; package HabrahabrApi; message KarmaRequest { string username = 1; } message KarmaResponse { string username = 1; float karma = 2; } message PostArticleRequest { string title = 1; string body = 2; repeated string tag = 3; repeated string hub = 4; } message PostArticleResponse { bool posted = 1; string url = 2; string time = 3; string error_code = 4; } service HabrApi { rpc GetKarma(KarmaRequest) returns (KarmaResponse) {} rpc PostArticle(PostArticleRequest) returns (PostArticleResponse) {} }
grpc \ vsprojects \ Debugãã©ã«ããŒã«ç§»åããããã§2ã€ã®ã³ãã³ããå®è¡ããŸãïŒãšããã§ãå ¬åŒããã¥ã¡ã³ãã§ã¯ãã®å Žæã«ãšã©ãŒããããåŒæ°ãæ£ãããããŸããïŒã
protoc --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin.exe habr.proto protoc --cpp_out=. habr.proto
åºåã§ã¯ã4ã€ã®ãã¡ã€ã«ãååŸããŸãã
- habr.pb.h
- habr.pb.cc
- habr.grpc.pb.h
- habr.grpc.pb.cc
ããã¯æšæž¬ããã®ãé£ãããªãã®ã§ãäžèšã®ãããã³ã«ã䜿çšããŠã¡ãã»ãŒãžã亀æã§ããå°æ¥ã®ã¯ã©ã€ã¢ã³ãããã³ãµãŒãã¹ã®ã¯ãŒã¯ããŒã¹ã§ãã
ãããžã§ã¯ããäœæããŸãããïŒ
- Visual Studioã§æ°ãããœãªã¥ãŒã·ã§ã³ãäœæããHabrAPIãšåŒã³ãŸãã
- 2ã€ã®ã³ã³ãœãŒã«ã¢ããªã±ãŒã·ã§ã³ãHabrServerãšHabrClientãè¿œå ããŸãã
- åã®æé ã§çæãããhããã³ssãã¡ã€ã«ããããã«è¿œå ããŸãã 4ã€ãã¹ãŠããµãŒããŒã«å«ããå¿ èŠããããã¯ã©ã€ã¢ã³ãã«ã¯habr.pb.hããã³habr.pb.ccã®ã¿ãå«ãŸããŸãã
- grpc \ third_party \ protobuf \ srcããã³grpc \ includeãã©ã«ããŒãžã®ãã¹ãè¿œå ãã©ã«ããŒã®è¿œå ã®ãããžã§ã¯ãèšå®ã«è¿œå ããŸãã
- è¿œå ã®ã©ã€ãã©ãªãã£ã¬ã¯ããªã®ãããžã§ã¯ãèšå®ã§grpc \ third_party \ protobuf \ cmake \ Debugã«ãã¹ãè¿œå ããŸãã
- è¿œå ã®äŸåé¢ä¿ã®ãããžã§ã¯ãèšå®ã«libprotobuf.libã©ã€ãã©ãªãè¿œå ããŸã
- ãªã³ã¯ã®ã¿ã€ãããProtobufãäœæãããã®ãšåãã¿ã€ãã«èšå®ããŸãïŒ[ã³ãŒãçæ]ã¿ãã®[ã©ã³ã¿ã€ã ã©ã€ãã©ãª]ããããã£ïŒã ãã®æç¹ã§ãå¿ èŠãªæ§æã§Protobufããã«ãããªãã£ãããšãå€æããå Žåããããæ»ã£ãŠåæ§ç¯ããå¿ èŠããããŸãã ç§ã¯ãã¡ãã¡ã§/ MTdãéžæããŸããã
- Nugetãä»ããŠzlibãšopensslã«äŸåé¢ä¿ãè¿œå ããŸãã
ä»ããã¹ãŠãé 調ã«é²ãã§ããŸãã 確ãã«ããŸã äœãæ©èœããŠããŸããã
ã客æ§
ããã§ã¯ãã¹ãŠãç°¡åã§ãã ãŸããhabr.pb.hã§çæãããã¹ã¿ãããç¶æ¿ãããã¯ã©ã¹ãäœæããå¿ èŠããããŸãã 次ã«ãGetKarmaã¡ãœãããšPostArticleã¡ãœãããå®è£ ããŸãã 第äžã«ãããããåŒã³åºããŠãããšãã°ãã³ã³ãœãŒã«ã«çµæã衚瀺ããŸãã 次ã®ããã«ãªããŸãã
#include <iostream> #include <memory> #include <string> #include <grpc/grpc.h> #include <grpc++/channel.h> #include <grpc++/client_context.h> #include <grpc++/create_channel.h> #include <grpc++/credentials.h> #include "habr.grpc.pb.h" using grpc::Channel; using grpc::ChannelArguments; using grpc::ClientContext; using grpc::Status; using HabrahabrApi::KarmaRequest; using HabrahabrApi::KarmaResponse; using HabrahabrApi::PostArticleRequest; using HabrahabrApi::PostArticleResponse; using HabrahabrApi::HabrApi; class HabrahabrClient { public: HabrahabrClient(std::shared_ptr<Channel> channel) : stub_(HabrApi::NewStub(channel)) {} float GetKarma(const std::string& username) { KarmaRequest request; request.set_username(username); KarmaResponse reply; ClientContext context; Status status = stub_->GetKarma(&context, request, &reply); if (status.ok()) { return reply.karma(); } else { return 0; } } bool PostArticle(const std::string& username) { PostArticleRequest request; request.set_title("Article about gRPC"); request.set_body("bla-bla-bla"); request.set_tag("UFO"); request.set_hab("Infopulse"); PostArticleResponse reply; ClientContext context; Status status = stub_->PostArticle(&context, request, &reply); return status.ok() && reply.posted(); } private: std::unique_ptr<HabrApi::Stub> stub_; }; int main(int argc, char** argv) { HabrahabrClient client( grpc::CreateChannel("localhost:50051", grpc::InsecureCredentials(), ChannelArguments())); std::string user("tangro"); std::string reply = client.GetKarma(user); std::cout << "Karma received: " << reply << std::endl; return 0; }
ãµãŒããŒ
ãµãŒããŒã«ãåæ§ã®è©±ããããŸã-habr.grpc.pb.hã§çæããããµãŒãã¹ã¯ã©ã¹ããç¶æ¿ãããã®ã¡ãœãããå®è£ ããŸãã 次ã«ãç¹å®ã®ããŒãã§ãªã¹ããŒãèµ·åãã顧客ãåŸ ã¡ãŸãã ãã®ãããªãã®ïŒ
#include <iostream> #include <memory> #include <string> #include <grpc/grpc.h> #include <grpc++/server.h> #include <grpc++/server_builder.h> #include <grpc++/server_context.h> #include <grpc++/server_credentials.h> #include "habr.grpc.pb.h" using grpc::Server; using grpc::ServerBuilder; using grpc::ServerContext; using grpc::Status; using HabrahabrApi::KarmaRequest; using HabrahabrApi::KarmaResponse; using HabrahabrApi::PostArticleRequest; using HabrahabrApi::PostArticleResponse; using HabrahabrApi::HabrApi; class HabrahabrServiceImpl final : public HabrApi::Service { Status GetKarma(ServerContext* context, const KarmaRequest* request, KarmaResponse* reply) override { reply->set_karma(42); return Status::OK; } Status PostArticle(ServerContext* context, const PostArticleRequest* request, PostArticleResponse* reply) override { reply->set_posted(true); reply->set_url("some_url"); return Status::OK; } }; void RunServer() { std::string server_address("0.0.0.0:50051"); HabrahabrServiceImpl 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; }
gRPCã䜿çšããŠé 匵ã£ãŠãã ããã