C++ gRPC library with protobuf and callback interface. It is easier to use than grpc++. It depends on grpc_cb_core.
- 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.lib
is in~/.conan/data/grpc_cb/0.2/jinq0123/testing/package/
...
- The result
- Or create:
conan create . user/channel --build missing
- The result
grpc_cb.lib
is in~/.conan/data/grpc_cb/0.2/user/channel/package/
...
- The result
(package: https://bintray.com/jinq0123/conan/grpc_cb%3Ajinq0123 )
See premake/README.md to use premake5 to generate VS solution.
- grpc_cpp_cb_plugin
- grpc_cb library
- helloworld example
- route_guide example
- Connect and disconnect event.
- Export for unity.
- Compression
- Security
- Metadata
Tutorial shows some codes in the route_guide example. See doc/advanced_usage.md for more usage examples.
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) {}
}
...
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
Stub
class for clients to call. - a
Service
class for servers to implement.
See examples/cpp_cb/route_guide/route_guide_cb_client.cc.
-
Create a shared
Channel
, specifying the server address.ChannelSptr channel(new Channel("localhost:50051"));
-
Instantiate a
Stub
Stub stub(channel);
- Sync call
-
Simple RPC:
SyncGetFeature()
Point point = MakePoint(0, 0); Feature feature; Status status = stub.SyncGetFeature(point, &feature);
-
Server-side streaming RPC:
SyncListFeatures()
auto sync_reader(stub_->SyncListFeatures(rect)); while (sync_reader.ReadOne(&feature)) { cout << feature.name() << endl; } Status status = sync_reader.RecvStatus();
-
Client-side streaming RPC:
SyncRecordRoute()
auto sync_writer(stub_->SyncRecordRoute()); for (int i = 0; i < kPoints; i++) { const Feature& f = GetRandomFeature(); if (!sync_writer.Write(f.location())) { // Broken stream. break; } } // Recv reponse and status. RouteSummary stats; Status status = sync_writer.Close(&stats);
-
Bidirectional streaming RPC:
SyncRouteChat()
auto sync_reader_writer(stub_->SyncRouteChat()); auto f = std::async(std::launch::async, [sync_reader_writer]() { RunWriteRouteNote(sync_reader_writer); }); RouteNote server_note; while (sync_reader_writer.ReadOne(&server_note)) PrintServerNote(server_note); f.wait(); Status status = sync_reader_writer.RecvStatus();
void 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
Point point = MakePoint(0, 0); stub.AsyncGetFeature(point, [](const Feature& feature) { PrintFeature(feature); });
-
Ignoring response
stub.AsyncGetFeature(point);
-
With error callback
stub.AsyncGetFeature(point, [](const Feature& feature) { PrintFeature(feature); }, [](const Status& err) { cout << err.GetDetails() << endl; }); // AsyncGetFeature()
-
-
Run the stub
-
Async calls need
stub.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()
stub.AsyncListFeatures(rect, [](const Feature& feature) { cout << feature.name() << endl; }, [&stub](const Status& status) { stub.Shutdown(); // To break Run(). }); stub.Run(); // until stub.Shutdown()
-
Client-side streaming RPC:
AsyncRecordRoute()
auto async_writer = stub.AsyncRecordRoute(); for (int i = 0; i < kPoints; i++) { const Feature& f = GetRandomFeature(); if (!async_writer.Write(f.location())) { break; } } // Recv reponse and status. async_writer.Close([](const Status& status, const RouteSummary& resp) { if (status.ok()) cout << resp.point_count() << endl; });
-
Bidirectional streaming RPC:
AsyncRouteChat()
std::atomic_bool bReaderDone = false; auto async_reader_writer( stub.AsyncRouteChat([&bReaderDone](const Status& status) { bReaderDone = true; })); async_reader_writer.ReadEach( [](const RouteNote& note) { PrintServerNote(note); }); std::vector<RouteNote> notes{ ... }; for (const RouteNote& note : notes) { async_reader_writer.Write(note); } async_reader_writer.CloseWriting();
-
See examples/cpp_cb/route_guide/route_guide_server.cc.
-
Define a
RouteGuideImpl
class that implements the generatedRouteGuide::Service
interface. Service is always asynchronous.class RouteGuideImpl final : public routeguide::RouteGuide::Service { ... }
-
Simple RPC:
GetFeature()
-
Reply immediately
void GetFeature(const Point& point, const GetFeature_Replier& replier) override { Feature feature; feature.set_name("..."); replier.Reply(feature); }
-
Reply later
void 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:
RecordRoute_ReaderSptr RecordRoute( RecordRoute_Replier replier) override { return std::make_shared<RecordRoute_ReaderImpl>(feature_vector_); } // RecordRoute()
-
Should implement a
RecordRoute_Reader
:class 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.
RouteChat_ReaderSptr RouteChat(RouteChat_Writer writer) override { return std::make_shared<Reader>(); }
- Implement a reader.
class 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.
-
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();