1 /*
2 *
3 * Copyright 2015 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19 #include <iostream>
20 #include <memory>
21 #include <string>
22 #include <thread>
23
24 #include "absl/flags/flag.h"
25 #include "absl/flags/parse.h"
26
27 #include <grpc/support/log.h>
28 #include <grpcpp/grpcpp.h>
29
30 #ifdef BAZEL_BUILD
31 #include "examples/protos/helloworld.grpc.pb.h"
32 #else
33 #include "helloworld.grpc.pb.h"
34 #endif
35
36 ABSL_FLAG(std::string, target, "localhost:50051", "Server address");
37
38 using grpc::Channel;
39 using grpc::ClientAsyncResponseReader;
40 using grpc::ClientContext;
41 using grpc::CompletionQueue;
42 using grpc::Status;
43 using helloworld::Greeter;
44 using helloworld::HelloReply;
45 using helloworld::HelloRequest;
46
47 class GreeterClient {
48 public:
GreeterClient(std::shared_ptr<Channel> channel)49 explicit GreeterClient(std::shared_ptr<Channel> channel)
50 : stub_(Greeter::NewStub(channel)) {}
51
52 // Assembles the client's payload and sends it to the server.
SayHello(const std::string & user)53 void SayHello(const std::string& user) {
54 // Data we are sending to the server.
55 HelloRequest request;
56 request.set_name(user);
57
58 // Call object to store rpc data
59 AsyncClientCall* call = new AsyncClientCall;
60
61 // stub_->PrepareAsyncSayHello() creates an RPC object, returning
62 // an instance to store in "call" but does not actually start the RPC
63 // Because we are using the asynchronous API, we need to hold on to
64 // the "call" instance in order to get updates on the ongoing RPC.
65 call->response_reader =
66 stub_->PrepareAsyncSayHello(&call->context, request, &cq_);
67
68 // StartCall initiates the RPC call
69 call->response_reader->StartCall();
70
71 // Request that, upon completion of the RPC, "reply" be updated with the
72 // server's response; "status" with the indication of whether the operation
73 // was successful. Tag the request with the memory address of the call
74 // object.
75 call->response_reader->Finish(&call->reply, &call->status, (void*)call);
76 }
77
78 // Loop while listening for completed responses.
79 // Prints out the response from the server.
AsyncCompleteRpc()80 void AsyncCompleteRpc() {
81 void* got_tag;
82 bool ok = false;
83
84 // Block until the next result is available in the completion queue "cq".
85 while (cq_.Next(&got_tag, &ok)) {
86 // The tag in this example is the memory location of the call object
87 AsyncClientCall* call = static_cast<AsyncClientCall*>(got_tag);
88
89 // Verify that the request was completed successfully. Note that "ok"
90 // corresponds solely to the request for updates introduced by Finish().
91 GPR_ASSERT(ok);
92
93 if (call->status.ok())
94 std::cout << "Greeter received: " << call->reply.message() << std::endl;
95 else
96 std::cout << "RPC failed" << std::endl;
97
98 // Once we're complete, deallocate the call object.
99 delete call;
100 }
101 }
102
103 private:
104 // struct for keeping state and data information
105 struct AsyncClientCall {
106 // Container for the data we expect from the server.
107 HelloReply reply;
108
109 // Context for the client. It could be used to convey extra information to
110 // the server and/or tweak certain RPC behaviors.
111 ClientContext context;
112
113 // Storage for the status of the RPC upon completion.
114 Status status;
115
116 std::unique_ptr<ClientAsyncResponseReader<HelloReply>> response_reader;
117 };
118
119 // Out of the passed in Channel comes the stub, stored here, our view of the
120 // server's exposed services.
121 std::unique_ptr<Greeter::Stub> stub_;
122
123 // The producer-consumer queue we use to communicate asynchronously with the
124 // gRPC runtime.
125 CompletionQueue cq_;
126 };
127
main(int argc,char ** argv)128 int main(int argc, char** argv) {
129 absl::ParseCommandLine(argc, argv);
130 // Instantiate the client. It requires a channel, out of which the actual RPCs
131 // are created. This channel models a connection to an endpoint specified by
132 // the argument "--target=" which is the only expected argument.
133 std::string target_str = absl::GetFlag(FLAGS_target);
134 // We indicate that the channel isn't authenticated (use of
135 // InsecureChannelCredentials()).
136 GreeterClient greeter(
137 grpc::CreateChannel(target_str, grpc::InsecureChannelCredentials()));
138
139 // Spawn reader thread that loops indefinitely
140 std::thread thread_ = std::thread(&GreeterClient::AsyncCompleteRpc, &greeter);
141
142 for (int i = 0; i < 100; i++) {
143 std::string user("world " + std::to_string(i));
144 greeter.SayHello(user); // The actual RPC call!
145 }
146
147 std::cout << "Press control-c to quit" << std::endl << std::endl;
148 thread_.join(); // blocks forever
149
150 return 0;
151 }
152