Home | History | Annotate | Download | only in helloworld
      1 # gRPC C++ Hello World Tutorial
      2 
      3 ### Install gRPC
      4 Make sure you have installed gRPC on your system. Follow the
      5 [BUILDING.md](../../../BUILDING.md) instructions.
      6 
      7 ### Get the tutorial source code
      8 
      9 The example code for this and our other examples lives in the `examples`
     10 directory. Clone this repository to your local machine by running the
     11 following command:
     12 
     13 
     14 ```sh
     15 $ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc
     16 ```
     17 
     18 Change your current directory to examples/cpp/helloworld
     19 
     20 ```sh
     21 $ cd examples/cpp/helloworld/
     22 ```
     23 
     24 ### Defining a service
     25 
     26 The first step in creating our example is to define a *service*: an RPC
     27 service specifies the methods that can be called remotely with their parameters
     28 and return types. As you saw in the
     29 [overview](#protocolbuffers) above, gRPC does this using [protocol
     30 buffers](https://developers.google.com/protocol-buffers/docs/overview). We
     31 use the protocol buffers interface definition language (IDL) to define our
     32 service methods, and define the parameters and return
     33 types as protocol buffer message types. Both the client and the
     34 server use interface code generated from the service definition.
     35 
     36 Here's our example service definition, defined using protocol buffers IDL in
     37 [helloworld.proto](../../protos/helloworld.proto). The `Greeting`
     38 service has one method, `hello`, that lets the server receive a single
     39 `HelloRequest`
     40 message from the remote client containing the user's name, then send back
     41 a greeting in a single `HelloReply`. This is the simplest type of RPC you
     42 can specify in gRPC - we'll look at some other types later in this document.
     43 
     44 ```protobuf
     45 syntax = "proto3";
     46 
     47 option java_package = "ex.grpc";
     48 
     49 package helloworld;
     50 
     51 // The greeting service definition.
     52 service Greeter {
     53   // Sends a greeting
     54   rpc SayHello (HelloRequest) returns (HelloReply) {}
     55 }
     56 
     57 // The request message containing the user's name.
     58 message HelloRequest {
     59   string name = 1;
     60 }
     61 
     62 // The response message containing the greetings
     63 message HelloReply {
     64   string message = 1;
     65 }
     66 
     67 ```
     68 
     69 <a name="generating"></a>
     70 ### Generating gRPC code
     71 
     72 Once we've defined our service, we use the protocol buffer compiler
     73 `protoc` to generate the special client and server code we need to create
     74 our application. The generated code contains both stub code for clients to
     75 use and an abstract interface for servers to implement, both with the method
     76 defined in our `Greeting` service.
     77 
     78 To generate the client and server side interfaces:
     79 
     80 ```sh
     81 $ make helloworld.grpc.pb.cc helloworld.pb.cc
     82 ```
     83 Which internally invokes the proto-compiler as:
     84 
     85 ```sh
     86 $ protoc -I ../../protos/ --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin ../../protos/helloworld.proto
     87 $ protoc -I ../../protos/ --cpp_out=. ../../protos/helloworld.proto
     88 ```
     89 
     90 ### Writing a client
     91 
     92 - Create a channel. A channel is a logical connection to an endpoint. A gRPC
     93   channel can be created with the target address, credentials to use and
     94   arguments as follows
     95 
     96     ```cpp
     97     auto channel = CreateChannel("localhost:50051", InsecureChannelCredentials());
     98     ```
     99 
    100 - Create a stub. A stub implements the rpc methods of a service and in the
    101   generated code, a method is provided to created a stub with a channel:
    102 
    103     ```cpp
    104     auto stub = helloworld::Greeter::NewStub(channel);
    105     ```
    106 
    107 - Make a unary rpc, with `ClientContext` and request/response proto messages.
    108 
    109     ```cpp
    110     ClientContext context;
    111     HelloRequest request;
    112     request.set_name("hello");
    113     HelloReply reply;
    114     Status status = stub->SayHello(&context, request, &reply);
    115     ```
    116 
    117 - Check returned status and response.
    118 
    119     ```cpp
    120     if (status.ok()) {
    121       // check reply.message()
    122     } else {
    123       // rpc failed.
    124     }
    125     ```
    126 
    127 For a working example, refer to [greeter_client.cc](greeter_client.cc).
    128 
    129 ### Writing a server
    130 
    131 - Implement the service interface
    132 
    133     ```cpp
    134     class GreeterServiceImpl final : public Greeter::Service {
    135       Status SayHello(ServerContext* context, const HelloRequest* request,
    136           HelloReply* reply) override {
    137         std::string prefix("Hello ");
    138         reply->set_message(prefix + request->name());
    139         return Status::OK;
    140       }
    141     };
    142 
    143     ```
    144 
    145 - Build a server exporting the service
    146 
    147     ```cpp
    148     GreeterServiceImpl service;
    149     ServerBuilder builder;
    150     builder.AddListeningPort("0.0.0.0:50051", grpc::InsecureServerCredentials());
    151     builder.RegisterService(&service);
    152     std::unique_ptr<Server> server(builder.BuildAndStart());
    153     ```
    154 
    155 For a working example, refer to [greeter_server.cc](greeter_server.cc).
    156 
    157 ### Writing asynchronous client and server
    158 
    159 gRPC uses `CompletionQueue` API for asynchronous operations. The basic work flow
    160 is
    161 - bind a `CompletionQueue` to a rpc call
    162 - do something like a read or write, present with a unique `void*` tag
    163 - call `CompletionQueue::Next` to wait for operations to complete. If a tag
    164   appears, it indicates that the corresponding operation is complete.
    165 
    166 #### Async client
    167 
    168 The channel and stub creation code is the same as the sync client.
    169 
    170 - Initiate the rpc and create a handle for the rpc. Bind the rpc to a
    171   `CompletionQueue`.
    172 
    173     ```cpp
    174     CompletionQueue cq;
    175     auto rpc = stub->AsyncSayHello(&context, request, &cq);
    176     ```
    177 
    178 - Ask for reply and final status, with a unique tag
    179 
    180     ```cpp
    181     Status status;
    182     rpc->Finish(&reply, &status, (void*)1);
    183     ```
    184 
    185 - Wait for the completion queue to return the next tag. The reply and status are
    186   ready once the tag passed into the corresponding `Finish()` call is returned.
    187 
    188     ```cpp
    189     void* got_tag;
    190     bool ok = false;
    191     cq.Next(&got_tag, &ok);
    192     if (ok && got_tag == (void*)1) {
    193       // check reply and status
    194     }
    195     ```
    196 
    197 For a working example, refer to [greeter_async_client.cc](greeter_async_client.cc).
    198 
    199 #### Async server
    200 
    201 The server implementation requests a rpc call with a tag and then wait for the
    202 completion queue to return the tag. The basic flow is
    203 
    204 - Build a server exporting the async service
    205 
    206     ```cpp
    207     helloworld::Greeter::AsyncService service;
    208     ServerBuilder builder;
    209     builder.AddListeningPort("0.0.0.0:50051", InsecureServerCredentials());
    210     builder.RegisterService(&service);
    211     auto cq = builder.AddCompletionQueue();
    212     auto server = builder.BuildAndStart();
    213     ```
    214 
    215 - Request one rpc
    216 
    217     ```cpp
    218     ServerContext context;
    219     HelloRequest request;
    220     ServerAsyncResponseWriter<HelloReply> responder;
    221     service.RequestSayHello(&context, &request, &responder, &cq, &cq, (void*)1);
    222     ```
    223 
    224 - Wait for the completion queue to return the tag. The context, request and
    225   responder are ready once the tag is retrieved.
    226 
    227     ```cpp
    228     HelloReply reply;
    229     Status status;
    230     void* got_tag;
    231     bool ok = false;
    232     cq.Next(&got_tag, &ok);
    233     if (ok && got_tag == (void*)1) {
    234       // set reply and status
    235       responder.Finish(reply, status, (void*)2);
    236     }
    237     ```
    238 
    239 - Wait for the completion queue to return the tag. The rpc is finished when the
    240   tag is back.
    241 
    242     ```cpp
    243     void* got_tag;
    244     bool ok = false;
    245     cq.Next(&got_tag, &ok);
    246     if (ok && got_tag == (void*)2) {
    247       // clean up
    248     }
    249     ```
    250 
    251 To handle multiple rpcs, the async server creates an object `CallData` to
    252 maintain the state of each rpc and use the address of it as the unique tag. For
    253 simplicity the server only uses one completion queue for all events, and runs a
    254 main loop in `HandleRpcs` to query the queue.
    255 
    256 For a working example, refer to [greeter_async_server.cc](greeter_async_server.cc).
    257 
    258 
    259 
    260 
    261