1 // Copyright 2023 gRPC authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <condition_variable> 16 #include <iostream> 17 #include <memory> 18 #include <mutex> 19 #include <string> 20 21 #include "absl/flags/flag.h" 22 #include "absl/flags/parse.h" 23 #include "absl/strings/str_format.h" 24 25 #include <grpcpp/generic/generic_stub.h> 26 #include <grpcpp/grpcpp.h> 27 28 #ifdef BAZEL_BUILD 29 #include "examples/protos/helloworld.grpc.pb.h" 30 #else 31 #include "helloworld.grpc.pb.h" 32 #endif 33 34 ABSL_FLAG(std::string, target, "localhost:50051", "Server address"); 35 36 using grpc::Channel; 37 using grpc::ClientContext; 38 using grpc::Status; 39 using helloworld::Greeter; 40 using helloworld::HelloReply; 41 using helloworld::HelloRequest; 42 43 using ProtoGenericStub = 44 ::grpc::TemplatedGenericStub<::google::protobuf::Message, 45 ::google::protobuf::Message>; 46 47 class GreeterClient { 48 public: GreeterClient(std::shared_ptr<Channel> channel)49 GreeterClient(std::shared_ptr<Channel> channel) 50 : stub_(new ProtoGenericStub(channel)) {} 51 52 // Assembles the client's payload, sends it and prints the response back 53 // from the server. SayHello(const std::string & user)54 void SayHello(const std::string& user) { 55 // Data we are sending to the server. 56 HelloRequest request; 57 request.set_name(user); 58 // Container for the data we expect from the server. 59 HelloReply reply; 60 // Context for the client. It could be used to convey extra information to 61 // the server and/or tweak certain RPC behaviors. 62 ClientContext context; 63 // The actual RPC. 64 std::mutex mu; 65 std::condition_variable cv; 66 bool done = false; 67 Status status; 68 std::cout << absl::StrFormat("### Send: SayHello(name=%s)", user) 69 << std::endl; 70 // Send a unary call using a generic stub. Unlike generated subs, 71 // this requires to specify the name of call. 72 stub_->UnaryCall(&context, "/helloworld.Greeter/SayHello", 73 grpc::StubOptions(), &request, &reply, [&](Status s) { 74 status = std::move(s); 75 std::lock_guard<std::mutex> lock(mu); 76 done = true; 77 cv.notify_one(); 78 }); 79 std::unique_lock<std::mutex> lock(mu); 80 while (!done) { 81 cv.wait(lock); 82 } 83 // Handles the reply 84 if (status.ok()) { 85 std::cout << absl::StrFormat("Ok. ReplyMessage=%s", reply.message()) 86 << std::endl; 87 } else { 88 std::cout << absl::StrFormat("Failed. Code=%d Message=%s", 89 status.error_code(), status.error_message()) 90 << std::endl; 91 } 92 } 93 94 private: 95 // Instead of `Greeter::Stub`, it uses `ProtoGenericStub` to send any calls. 96 std::unique_ptr<ProtoGenericStub> stub_; 97 }; 98 main(int argc,char ** argv)99 int main(int argc, char** argv) { 100 absl::ParseCommandLine(argc, argv); 101 // Instantiate the client. It requires a channel, out of which the actual RPCs 102 // are created. This channel models a connection to an endpoint specified by 103 // the argument "--target=" which is the only expected argument. 104 std::string target_str = absl::GetFlag(FLAGS_target); 105 // We indicate that the channel isn't authenticated (use of 106 // InsecureChannelCredentials()). 107 GreeterClient greeter( 108 grpc::CreateChannel(target_str, grpc::InsecureChannelCredentials())); 109 greeter.SayHello("World"); 110 greeter.SayHello("gRPC"); 111 return 0; 112 } 113