aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar yang-g <yangg@google.com>2015-08-26 15:08:43 -0700
committerGravatar yang-g <yangg@google.com>2015-08-26 16:31:38 -0700
commit0c63351381c17f5a5f26cfef1328d4fd62ba646b (patch)
treef0a4be834979017f2e7ec8f9f71a5df94fe8e63f
parentbcd57fc78d99bb680ca46502e12df2d7cd1fdf53 (diff)
sync and async doc
-rw-r--r--cpp/helloworld/README.md168
1 files changed, 166 insertions, 2 deletions
diff --git a/cpp/helloworld/README.md b/cpp/helloworld/README.md
index bc7df3f8c7..ad98001f87 100644
--- a/cpp/helloworld/README.md
+++ b/cpp/helloworld/README.md
@@ -89,8 +89,172 @@ $ protoc -I ../../protos/ --cpp_out=. ../../protos/helloworld.proto
### Writing a client
-This is an incomplete tutorial. For now the reader should refer to [greeter_client.cc](https://github.com/grpc/grpc-common/blob/master/cpp/helloworld/greeter_client.cc).
+- Create a channel. A channel is a logical connection to an endpoint. A gRPC
+ channel can be created with the target address, credentials to use and
+ arguments as follows
+
+ ```
+ auto channel = CreateChannel("localhost:50051", InsecureCredentials(), ChannelArguments());
+ ```
+
+- Create a stub. A stub implements the rpc methods of a service and in the
+ generated code, a method is provided to created a stub with a channel:
+
+ ```
+ auto stub = helloworld::Greeter::NewStub(channel);
+ ```
+
+- Make a unary rpc, with `ClientContext` and request/response proto messages.
+
+ ```
+ ClientContext context;
+ HelloRequest request;
+ request.set_name("hello");
+ HelloReply reply;
+ Status status = stub->SayHello(&context, request, &reply);
+ ```
+
+- Check returned status and response.
+
+ ```
+ if (status.ok()) {
+ // check reply.message()
+ } else {
+ // rpc failed.
+ }
+ ```
+
+For a working example, refer to [greeter_client.cc](https://github.com/grpc/grpc-common/blob/master/cpp/helloworld/greeter_client.cc).
### Writing a server
-This is an incomplete tutorial. For now the reader should refer to [greeter_server.cc](https://github.com/grpc/grpc-common/blob/master/cpp/helloworld/greeter_server.cc).
+- Implement the service interface
+
+ ```
+ class GreeterServiceImpl final : public Greeter::Service {
+ Status SayHello(ServerContext* context, const HelloRequest* request,
+ HelloReply* reply) override {
+ std::string prefix("Hello ");
+ reply->set_message(prefix + request->name());
+ return Status::OK;
+ }
+ };
+
+ ```
+
+- Build a server exporting the service
+
+ ```
+ GreeterServiceImpl service;
+ ServerBuilder builder;
+ builder.AddListeningPort("0.0.0.0:50051", grpc::InsecureServerCredentials());
+ builder.RegisterService(&service);
+ std::unique_ptr<Server> server(builder.BuildAndStart());
+ ```
+
+For a working example, refer to [greeter_server.cc](https://github.com/grpc/grpc-common/blob/master/cpp/helloworld/greeter_server.cc).
+
+### Writing asynchronous client and server
+
+gRPC uses `CompletionQueue` API for asynchronous operations. The basic work flow
+is
+- bind a `CompletionQueue` to a rpc call
+- do something like a read or write, present with a unique `void*` tag
+- call `CompletionQueue::Next` to poll the events. If the tag appears, the
+ previous operation finishes.
+
+#### Async client
+
+The channel and stub creation code is the same as the sync client.
+
+- Initiate the rpc and create a handle for the rpc. Bind a `CompletionQueue` to
+ it.
+
+ ```
+ CompletionQueue cq;
+ auto rpc = stub->AsyncSayHello(&context, request, &cq);
+ ```
+
+- Ask for reply and final status, with a unique tag
+
+ ```
+ Status status;
+ rpc->Finish(&reply, &status, (void*)1);
+ ```
+
+- Poll the completion queue for the tag. The reply and status are ready once the
+ tag is returned.
+
+ ```
+ void* got_tag;
+ bool ok = false;
+ cq.Next(&got_tag, &ok);
+ if (ok && got_tag == (void*)1) {
+ // check reply and status
+ }
+ ```
+
+For a working example, refer to [greeter_async_client.cc](https://github.com/grpc/grpc-common/blob/master/cpp/helloworld/greeter_async_client.cc).
+
+#### Async server
+
+The server implementation requests a rpc call with a tag and then poll the
+completion queue for the tag. The basic flow is
+
+- Build a server exporting the async service
+
+ ```
+ helloworld::Greeter::AsyncService service;
+ ServerBuilder builder;
+ builder.AddListeningPort("0.0.0.0:50051", InsecureServerCredentials());
+ builder.RegisterAsyncService(&service);
+ auto cq = builder.AddCompletionQueue();
+ auto server = builder.BuildAndStart();
+ ```
+
+- Request one rpc
+
+ ```
+ ServerContext context;
+ HelloRequest request;
+ ServerAsyncResponseWriter<HelloReply> responder;
+ service.RequestSayHello(&context, &request, &responder, &cq, &cq, (void*)1);
+ ```
+
+- Poll the completion queue for the tag. The context, request and responder are
+ ready once the tag is retrieved.
+
+ ```
+ HelloReply reply;
+ Status status;
+ void* got_tag;
+ bool ok = false;
+ cq.Next(&got_tag, &ok);
+ if (ok && got_tag == (void*)1) {
+ // set reply and status
+ responder.Finish(reply, status, (void*)2);
+ }
+ ```
+
+- Poll the completion queue for the tag. The rpc is finished when the tag is
+ back.
+
+ ```
+ void* got_tag;
+ bool ok = false;
+ cq.Next(&got_tag, &ok);
+ if (ok && got_tag == (void*)2) {
+ // clean up
+ }
+ ```
+
+To handle multiple rpcs, the async server creates an object `CallData` to
+maintain the state of each rpc and use the address of it as the unique tag. For
+simplicity the server only uses one completion queue for all events, and runs a
+main loop in `HandleRpcs` to query the queue.
+
+For a working example, refer to [greeter_async_server.cc](https://github.com/grpc/grpc-common/blob/master/cpp/helloworld/greeter_async_server.cc).
+
+
+
+