| Index: third_party/grpc/examples/cpp/helloworld/README.md
|
| diff --git a/third_party/grpc/examples/cpp/helloworld/README.md b/third_party/grpc/examples/cpp/helloworld/README.md
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8e11f7cdf3ee893858d261c75c4586aa13b16b1c
|
| --- /dev/null
|
| +++ b/third_party/grpc/examples/cpp/helloworld/README.md
|
| @@ -0,0 +1,260 @@
|
| +# gRPC C++ Hello World Tutorial
|
| +
|
| +### Install gRPC
|
| +Make sure you have installed gRPC on your system. Follow the instructions here:
|
| +[https://github.com/grpc/grpc/blob/master/INSTALL](../../../INSTALL.md).
|
| +
|
| +### Get the tutorial source code
|
| +
|
| +The example code for this and our other examples lives in the `examples`
|
| +directory. Clone this repository to your local machine by running the
|
| +following command:
|
| +
|
| +
|
| +```sh
|
| +$ git clone https://github.com/grpc/grpc.git
|
| +```
|
| +
|
| +Change your current directory to examples/cpp/helloworld
|
| +
|
| +```sh
|
| +$ cd examples/cpp/helloworld/
|
| +```
|
| +
|
| +### Defining a service
|
| +
|
| +The first step in creating our example is to define a *service*: an RPC
|
| +service specifies the methods that can be called remotely with their parameters
|
| +and return types. As you saw in the
|
| +[overview](#protocolbuffers) above, gRPC does this using [protocol
|
| +buffers](https://developers.google.com/protocol-buffers/docs/overview). We
|
| +use the protocol buffers interface definition language (IDL) to define our
|
| +service methods, and define the parameters and return
|
| +types as protocol buffer message types. Both the client and the
|
| +server use interface code generated from the service definition.
|
| +
|
| +Here's our example service definition, defined using protocol buffers IDL in
|
| +[helloworld.proto](../../protos/helloworld.proto). The `Greeting`
|
| +service has one method, `hello`, that lets the server receive a single
|
| +`HelloRequest`
|
| +message from the remote client containing the user's name, then send back
|
| +a greeting in a single `HelloReply`. This is the simplest type of RPC you
|
| +can specify in gRPC - we'll look at some other types later in this document.
|
| +
|
| +```protobuf
|
| +syntax = "proto3";
|
| +
|
| +option java_package = "ex.grpc";
|
| +
|
| +package helloworld;
|
| +
|
| +// The greeting service definition.
|
| +service Greeter {
|
| + // Sends a greeting
|
| + rpc SayHello (HelloRequest) returns (HelloReply) {}
|
| +}
|
| +
|
| +// The request message containing the user's name.
|
| +message HelloRequest {
|
| + string name = 1;
|
| +}
|
| +
|
| +// The response message containing the greetings
|
| +message HelloReply {
|
| + string message = 1;
|
| +}
|
| +
|
| +```
|
| +
|
| +<a name="generating"></a>
|
| +### Generating gRPC code
|
| +
|
| +Once we've defined our service, we use the protocol buffer compiler
|
| +`protoc` to generate the special client and server code we need to create
|
| +our application. The generated code contains both stub code for clients to
|
| +use and an abstract interface for servers to implement, both with the method
|
| +defined in our `Greeting` service.
|
| +
|
| +To generate the client and server side interfaces:
|
| +
|
| +```sh
|
| +$ make helloworld.grpc.pb.cc helloworld.pb.cc
|
| +```
|
| +Which internally invokes the proto-compiler as:
|
| +
|
| +```sh
|
| +$ protoc -I ../../protos/ --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin ../../protos/helloworld.proto
|
| +$ protoc -I ../../protos/ --cpp_out=. ../../protos/helloworld.proto
|
| +```
|
| +
|
| +### Writing a client
|
| +
|
| +- 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
|
| +
|
| + ```cpp
|
| + auto channel = CreateChannel("localhost:50051", InsecureChannelCredentials());
|
| + ```
|
| +
|
| +- 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:
|
| +
|
| + ```cpp
|
| + auto stub = helloworld::Greeter::NewStub(channel);
|
| + ```
|
| +
|
| +- Make a unary rpc, with `ClientContext` and request/response proto messages.
|
| +
|
| + ```cpp
|
| + ClientContext context;
|
| + HelloRequest request;
|
| + request.set_name("hello");
|
| + HelloReply reply;
|
| + Status status = stub->SayHello(&context, request, &reply);
|
| + ```
|
| +
|
| +- Check returned status and response.
|
| +
|
| + ```cpp
|
| + if (status.ok()) {
|
| + // check reply.message()
|
| + } else {
|
| + // rpc failed.
|
| + }
|
| + ```
|
| +
|
| +For a working example, refer to [greeter_client.cc](greeter_client.cc).
|
| +
|
| +### Writing a server
|
| +
|
| +- Implement the service interface
|
| +
|
| + ```cpp
|
| + 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
|
| +
|
| + ```cpp
|
| + 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](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 wait for operations to complete. If a tag
|
| + appears, it indicates that the corresponding operation is complete.
|
| +
|
| +#### 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 the rpc to a
|
| + `CompletionQueue`.
|
| +
|
| + ```cpp
|
| + CompletionQueue cq;
|
| + auto rpc = stub->AsyncSayHello(&context, request, &cq);
|
| + ```
|
| +
|
| +- Ask for reply and final status, with a unique tag
|
| +
|
| + ```cpp
|
| + Status status;
|
| + rpc->Finish(&reply, &status, (void*)1);
|
| + ```
|
| +
|
| +- Wait for the completion queue to return the next tag. The reply and status are
|
| + ready once the tag passed into the corresponding `Finish()` call is returned.
|
| +
|
| + ```cpp
|
| + 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](greeter_async_client.cc).
|
| +
|
| +#### Async server
|
| +
|
| +The server implementation requests a rpc call with a tag and then wait for the
|
| +completion queue to return the tag. The basic flow is
|
| +
|
| +- Build a server exporting the async service
|
| +
|
| + ```cpp
|
| + 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
|
| +
|
| + ```cpp
|
| + ServerContext context;
|
| + HelloRequest request;
|
| + ServerAsyncResponseWriter<HelloReply> responder;
|
| + service.RequestSayHello(&context, &request, &responder, &cq, &cq, (void*)1);
|
| + ```
|
| +
|
| +- Wait for the completion queue to return the tag. The context, request and
|
| + responder are ready once the tag is retrieved.
|
| +
|
| + ```cpp
|
| + 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);
|
| + }
|
| + ```
|
| +
|
| +- Wait for the completion queue to return the tag. The rpc is finished when the
|
| + tag is back.
|
| +
|
| + ```cpp
|
| + 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](greeter_async_server.cc).
|
| +
|
| +
|
| +
|
| +
|
|
|