| # 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 -b $(curl -L http://grpc.io/release) https://github.com/grpc/grpc | |
| ``` | |
| 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.RegisterService(&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). | |