grpc_cb
grpc_cb copied to clipboard
C++ gRPC library with callback interface.
gRPC_cb
C++ gRPC library with protobuf and callback interface. It is easier to use than grpc++. It depends on grpc_cb_core.
Install with conan
- Install conan.
- Add conan repository:
conan remote add remote_bintray_jinq0123 https://api.bintray.com/conan/jinq0123/conan - Install:
conan install grpc_cb/0.2@jinq0123/testing- The result
grpc_cb.libis in~/.conan/data/grpc_cb/0.2/jinq0123/testing/package/...
- The result
- Or create:
conan create . user/channel --build missing- The result
grpc_cb.libis in~/.conan/data/grpc_cb/0.2/user/channel/package/...
- The result
(package: https://bintray.com/jinq0123/conan/grpc_cb%3Ajinq0123 )
VS solution
See premake/README.md to use premake5 to generate VS solution.
Done
- grpc_cpp_cb_plugin
- grpc_cb library
- helloworld example
- route_guide example
Todo
- Connect and disconnect event.
- Export for unity.
- Compression
- Security
- Metadata
Tutorial
Tutorial shows some codes in the route_guide example. See doc/advanced_usage.md for more usage examples.
Defining the service
See examples/protos/route_guide.proto.
// Interface exported by the server.
service RouteGuide {
// A simple RPC.
rpc GetFeature(Point) returns (Feature) {}
// A server-to-client streaming RPC.
rpc ListFeatures(Rectangle) returns (stream Feature) {}
// A client-to-server streaming RPC.
rpc RecordRoute(stream Point) returns (RouteSummary) {}
// A Bidirectional streaming RPC.
rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
}
...
Generating client and server code
examples/protos/generate.bat is an example to generate client and server interfaces from .proto file, which runs:
protoc -I . --cpp_out=../cpp_cb/route_guide route_guide.proto
protoc -I . --grpc_out=../cpp_cb/route_guide --plugin=protoc-gen-grpc=grpc_cpp_cb_plugin.exe route_guide.proto
This generates the following files in directory examples/cpp_cb/route_guide
route_guide.pb.h, generated message classes headerroute_guide.pb.cc, the implementation of message classesroute_guide.grpc_cb.pb.h, generated service classes headerroute_guide.grpc_cb.pb.cc, the implementation of service classes
The generated namespace RouteGuide contains
- a
Stubclass for clients to call. - a
Serviceclass for servers to implement.
Creating the client
See examples/cpp_cb/route_guide/route_guide_cb_client.cc.
Creating a stub
-
Create a shared
Channel, specifying the server address.ChannelSptr channel(new Channel("localhost:50051")); -
Instantiate a
StubStub stub(channel);
Calling service methods
- Sync call
-
Simple RPC:
SyncGetFeature()oint point = MakePoint(0, 0); eature feature; tatus status = stub.SyncGetFeature(point, &feature); -
Server-side streaming RPC:
SyncListFeatures()uto sync_reader(stub_->SyncListFeatures(rect)); hile (sync_reader.ReadOne(&feature)) { cout << feature.name() << endl; tatus status = sync_reader.RecvStatus(); -
Client-side streaming RPC:
SyncRecordRoute()uto sync_writer(stub_->SyncRecordRoute()); or (int i = 0; i < kPoints; i++) { const Feature& f = GetRandomFeature(); if (!sync_writer.Write(f.location())) { // Broken stream. break; } / Recv reponse and status. outeSummary stats; tatus status = sync_writer.Close(&stats); -
Bidirectional streaming RPC:
SyncRouteChat()uto sync_reader_writer(stub_->SyncRouteChat()); uto f = std::async(std::launch::async, [sync_reader_writer]() { RunWriteRouteNote(sync_reader_writer); ); outeNote server_note; hile (sync_reader_writer.ReadOne(&server_note)) PrintServerNote(server_note); .wait(); tatus status = sync_reader_writer.RecvStatus();oid RunWriteRouteNote(Stus::RouteChat_SyncReaderWriter sync_reader_writer) { std::vector<RouteNote> notes{ ... }; for (const RouteNote& note : notes) { sync_reader_writer.Write(note); RandomSleep(); } sync_reader_writer.CloseWriting();
-
- Asycn call
-
Simple RPC:
AsyncGetFeature()-
With response callback
oint point = MakePoint(0, 0); tub.AsyncGetFeature(point, [](const Feature& feature) { PrintFeature(feature); }); -
Ignoring response
tub.AsyncGetFeature(point); -
With error callback
tub.AsyncGetFeature(point, [](const Feature& feature) { PrintFeature(feature); }, [](const Status& err) { cout << err.GetDetails() << endl; }); // AsyncGetFeature()
-
-
Run the stub
-
Async calls need
tub.Run(); // until stub.Shutdown() -
It can run in other thread.
-
It can be before or after async calls.
-
stub.Shutdown()or~Stub()to endstub.Run().
-
-
Server-side streaming RPC:
AsyncListFeatures()tub.AsyncListFeatures(rect, [](const Feature& feature) { cout << feature.name() << endl; }, [&stub](const Status& status) { stub.Shutdown(); // To break Run(). }); tub.Run(); // until stub.Shutdown() -
Client-side streaming RPC:
AsyncRecordRoute()uto async_writer = stub.AsyncRecordRoute(); or (int i = 0; i < kPoints; i++) { const Feature& f = GetRandomFeature(); if (!async_writer.Write(f.location())) { break; } / Recv reponse and status. sync_writer.Close([](const Status& status, const RouteSummary& resp) { if (status.ok()) cout << resp.point_count() << endl; ); -
Bidirectional streaming RPC:
AsyncRouteChat()td::atomic_bool bReaderDone = false; uto async_reader_writer( stub.AsyncRouteChat([&bReaderDone](const Status& status) { bReaderDone = true; })); sync_reader_writer.ReadEach( [](const RouteNote& note) { PrintServerNote(note); }); td::vector<RouteNote> notes{ ... }; or (const RouteNote& note : notes) { async_reader_writer.Write(note); sync_reader_writer.CloseWriting();
-
Creating the server
See examples/cpp_cb/route_guide/route_guide_server.cc.
Implementing RouteGuide service
-
Define a
RouteGuideImplclass that implements the generatedRouteGuide::Serviceinterface. Service is always asynchronous.class RouteGuideImpl final : public routeguide::RouteGuide::Service { ... } -
Simple RPC:
GetFeature()-
Reply immediately
oid GetFeature(const Point& point, const GetFeature_Replier& replier) override { Feature feature; feature.set_name("..."); replier.Reply(feature); -
Reply later
oid GetFeature(const Point& point, const GetFeature_Replier& replier) override { GetFeature_Replier replier_copy(replier); std::thread thd([replier_copy]() { Sleep(1000); Feature feature; feature.set_name("..."); replier_copy.Reply(feature); }); thd.detach();
-
-
Server-side streaming RPC:
ListFeatures()void ListFeatures(const routeguide::Rectangle& rectangle, ListFeatures_Writer writer) override { std::thread t([writer]() { for (const Feature& f : feature_vector) { if (!writer.Write(f)) break; Sleep(1000); } }); // thread t t.detach(); } -
Client-side streaming RPC:
RecordRoute()-
Should return a shared reader:
ecordRoute_ReaderSptr RecordRoute( RecordRoute_Replier replier) override { return std::make_shared<RecordRoute_ReaderImpl>(feature_vector_); // RecordRoute() -
Should implement a
RecordRoute_Reader:lass RecordRoute_ReaderImpl : public routeguide::RouteGuide::Service::RecordRoute_Reader { ... -
Implement virtual methods
OnMsg(const Request& msg)- Default noop.
OnError(const Status& status)- Default replys error.
OnEnd()- Default noop.
-
-
Bidirectional streaming RPC:
RouteChat()- Should return a shared reader.
outeChat_ReaderSptr RouteChat(RouteChat_Writer writer) override { return std::make_shared<Reader>(); - Implement a reader.
lass Reader : public RouteChat_Reader { protected: void OnMsg(const RouteNote& msg) override { for (const RouteNote& n : received_notes_) { GetWriter().Write(n); } // for received_notes_.push_back(msg); } // OnMsg() void OnEnd() override { RouteChat_Writer writer = GetWriter(); std::thread t([writer]() { std::this_thread::sleep_for(std::chrono::seconds(1)); writer.Write(RouteNote()); }); t.detach(); } // OnEnd() private: std::vector<RouteNote> received_notes_; ; // class Reader
- Should return a shared reader.
Starting the server
-
Instantiate server and add listening port.
Server svr; svr.AddListeningPort("0.0.0.0:50051"); -
Instantiate service and register to server.
RouteGuideImpl service(db_path); svr.RegisterService(service); -
Blocking run server.
svr.Run();