├── .gitignore ├── grpc ├── CMakeLists.txt ├── greetings │ ├── CMakeLists.txt │ ├── greetings_server.cc │ └── greetings_client.cc └── arithmetics │ ├── CMakeLists.txt │ ├── arithmetics_server.cc │ └── arithmetics_client.cc ├── protos ├── greetings.proto └── arithmetics.proto ├── CMakeLists.txt ├── LICENSE.md ├── docker └── grpc.Dockerfile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | build -------------------------------------------------------------------------------- /grpc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Minimum CMake required 2 | cmake_minimum_required(VERSION 3.13) 3 | 4 | project(gRPC_CPP_Examples VERSION 0.0.1 LANGUAGES CXX) 5 | set(CMAKE_CXX_STANDARD 14) 6 | set(CMAKE_BUILD_TYPE RelWithDebInfo) 7 | 8 | # Set examples list 9 | set(examples greetings arithmetics) 10 | 11 | foreach(example ${examples}) 12 | add_subdirectory(${example}) 13 | endforeach() 14 | -------------------------------------------------------------------------------- /protos/greetings.proto: -------------------------------------------------------------------------------- 1 | // [START declaration] 2 | syntax = "proto3"; 3 | // Namespace 4 | package greetings; 5 | // [END declaration] 6 | 7 | // [START service] 8 | // The greeting service definition. 9 | service Greeter { 10 | // Sends a greeting 11 | rpc SayHello (HelloRequest) returns (HelloReply) {} 12 | } 13 | // [END service] 14 | 15 | // [START messages] 16 | // The request message containing the user's name. 17 | message HelloRequest { 18 | string name = 1; 19 | } 20 | 21 | // The response message containing the greetings. 22 | message HelloReply { 23 | string message = 1; 24 | } 25 | // [END messages] -------------------------------------------------------------------------------- /protos/arithmetics.proto: -------------------------------------------------------------------------------- 1 | // [START declaration] 2 | syntax = "proto3"; 3 | // Namespace 4 | package arithmetics; 5 | // [END declaration] 6 | 7 | // [START service] 8 | // The arithmetic service definition. 9 | service Arithmetics { 10 | rpc Add (TwoValueRequest) returns (OneValueReply) {} 11 | rpc Minus (TwoValueRequest) returns (OneValueReply) {} 12 | rpc Multiply (TwoValueRequest) returns (OneValueReply) {} 13 | rpc Divide (TwoValueRequest) returns (OneValueReply) {} 14 | } 15 | // [END service] 16 | 17 | // [START messages] 18 | // The request message containing two integer values. 19 | message TwoValueRequest { 20 | int32 a = 1; 21 | int32 b = 2; 22 | } 23 | 24 | // The response message containing one integer value. 25 | message OneValueReply { 26 | int32 c = 1; 27 | } 28 | // [END messages] -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Minimum CMake required 2 | cmake_minimum_required(VERSION 3.13) 3 | 4 | project(gRPC_Examples VERSION 0.0.1 LANGUAGES CXX) 5 | set(CMAKE_CXX_STANDARD 14) 6 | set(CMAKE_BUILD_TYPE RelWithDebInfo) 7 | 8 | set(protobuf_MODULE_COMPATIBLE TRUE) 9 | find_package(Protobuf CONFIG REQUIRED) 10 | message(STATUS "Using protobuf ${Protobuf_VERSION}") 11 | 12 | set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf) 13 | set(_REFLECTION gRPC::grpc++_reflection) 14 | if(CMAKE_CROSSCOMPILING) 15 | find_program(_PROTOBUF_PROTOC protoc) 16 | else() 17 | set(_PROTOBUF_PROTOC $) 18 | endif() 19 | 20 | # Find gRPC installation 21 | # Looks for gRPCConfig.cmake file installed by gRPC's cmake installation. 22 | find_package(gRPC CONFIG REQUIRED) 23 | message(STATUS "Using gRPC ${gRPC_VERSION}") 24 | 25 | set(_GRPC_GRPCPP gRPC::grpc++) 26 | if(CMAKE_CROSSCOMPILING) 27 | find_program(_GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin) 28 | else() 29 | set(_GRPC_CPP_PLUGIN_EXECUTABLE $) 30 | endif() 31 | 32 | # Add example projects 33 | add_subdirectory(grpc) -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2019 Lei Mao 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /docker/grpc.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:20.04 2 | 3 | LABEL maintainer="Lei Mao " 4 | 5 | ARG GPRC_VERSION=1.34.0 6 | ARG NUM_JOBS=8 7 | 8 | ENV DEBIAN_FRONTEND noninteractive 9 | 10 | # Install package dependencies 11 | RUN apt-get update && apt-get install -y --no-install-recommends \ 12 | build-essential \ 13 | software-properties-common \ 14 | autoconf \ 15 | automake \ 16 | libtool \ 17 | pkg-config \ 18 | ca-certificates \ 19 | wget \ 20 | git \ 21 | curl \ 22 | vim \ 23 | gdb \ 24 | valgrind \ 25 | cmake 26 | RUN apt-get clean 27 | 28 | # gRPC 29 | # https://github.com/grpc/grpc/tree/master/src/cpp 30 | # https://github.com/grpc/grpc/blob/master/BUILDING.md 31 | RUN cd /tmp && \ 32 | apt-get install -y build-essential autoconf libtool pkg-config && \ 33 | git clone --recurse-submodules -b v${GPRC_VERSION} https://github.com/grpc/grpc && \ 34 | cd grpc && \ 35 | mkdir -p cmake/build && \ 36 | cd cmake/build && \ 37 | cmake -DgRPC_INSTALL=ON \ 38 | -DgRPC_BUILD_TESTS=OFF \ 39 | -DCMAKE_INSTALL_PREFIX=$MY_INSTALL_DIR \ 40 | ../.. && \ 41 | make -j${NUM_JOBS} && \ 42 | make install 43 | -------------------------------------------------------------------------------- /grpc/greetings/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Minimum CMake required 2 | cmake_minimum_required(VERSION 3.13) 3 | 4 | project(gRPC_CPP_Greetings VERSION 0.0.1 LANGUAGES CXX) 5 | set(CMAKE_CXX_STANDARD 14) 6 | set(CMAKE_BUILD_TYPE RelWithDebInfo) 7 | 8 | set (proto_name greetings) 9 | 10 | # Get proto files 11 | get_filename_component(proto "../../protos/${proto_name}.proto" ABSOLUTE) 12 | get_filename_component(proto_dir "${proto}" DIRECTORY) 13 | 14 | # Generate source files 15 | set(proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/${proto_name}.pb.cc") 16 | set(proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/${proto_name}.pb.h") 17 | set(grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/${proto_name}.grpc.pb.cc") 18 | set(grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/${proto_name}.grpc.pb.h") 19 | add_custom_command( 20 | OUTPUT "${proto_srcs}" "${proto_hdrs}" "${grpc_srcs}" "${grpc_hdrs}" 21 | COMMAND ${_PROTOBUF_PROTOC} 22 | ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}" 23 | --cpp_out "${CMAKE_CURRENT_BINARY_DIR}" 24 | -I "${proto_dir}" 25 | --plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}" 26 | "${proto}" 27 | DEPENDS "${proto}" 28 | ) 29 | 30 | set(targets "${proto_name}_server" "${proto_name}_client") 31 | 32 | # Include generated *.pb.h files 33 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 34 | 35 | foreach(target ${targets}) 36 | add_executable(${target} "${target}.cc" ${proto_srcs} ${grpc_srcs}) 37 | target_link_libraries(${target} PRIVATE ${_REFLECTION} ${_GRPC_GRPCPP} ${_PROTOBUF_LIBPROTOBUF}) 38 | # Cannot do this because these directories are not available during CMake "compile time" 39 | # target_include_directories(${proto_hdrs} ${grpc_hdrs}) 40 | endforeach() 41 | 42 | -------------------------------------------------------------------------------- /grpc/arithmetics/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Minimum CMake required 2 | cmake_minimum_required(VERSION 3.13) 3 | 4 | project(gRPC_CPP_Arithmetics VERSION 0.0.1 LANGUAGES CXX) 5 | set(CMAKE_CXX_STANDARD 14) 6 | set(CMAKE_BUILD_TYPE RelWithDebInfo) 7 | 8 | set (proto_name arithmetics) 9 | 10 | # Get proto files 11 | get_filename_component(proto "../../protos/${proto_name}.proto" ABSOLUTE) 12 | get_filename_component(proto_dir "${proto}" DIRECTORY) 13 | 14 | # Generate source files 15 | set(proto_srcs "${CMAKE_CURRENT_BINARY_DIR}/${proto_name}.pb.cc") 16 | set(proto_hdrs "${CMAKE_CURRENT_BINARY_DIR}/${proto_name}.pb.h") 17 | set(grpc_srcs "${CMAKE_CURRENT_BINARY_DIR}/${proto_name}.grpc.pb.cc") 18 | set(grpc_hdrs "${CMAKE_CURRENT_BINARY_DIR}/${proto_name}.grpc.pb.h") 19 | add_custom_command( 20 | OUTPUT "${proto_srcs}" "${proto_hdrs}" "${grpc_srcs}" "${grpc_hdrs}" 21 | COMMAND ${_PROTOBUF_PROTOC} 22 | ARGS --grpc_out "${CMAKE_CURRENT_BINARY_DIR}" 23 | --cpp_out "${CMAKE_CURRENT_BINARY_DIR}" 24 | -I "${proto_dir}" 25 | --plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}" 26 | "${proto}" 27 | DEPENDS "${proto}" 28 | ) 29 | 30 | set(targets "${proto_name}_server" "${proto_name}_client") 31 | 32 | # Include generated *.pb.h files 33 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 34 | 35 | foreach(target ${targets}) 36 | add_executable(${target} "${target}.cc" ${proto_srcs} ${grpc_srcs}) 37 | target_link_libraries(${target} PRIVATE ${_REFLECTION} ${_GRPC_GRPCPP} ${_PROTOBUF_LIBPROTOBUF}) 38 | # Cannot do this because these directories are not available during CMake "compile time" 39 | # target_include_directories(${proto_hdrs} ${grpc_hdrs}) 40 | endforeach() 41 | 42 | -------------------------------------------------------------------------------- /grpc/greetings/greetings_server.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include "greetings.grpc.pb.h" 8 | 9 | using grpc::Server; 10 | using grpc::ServerBuilder; 11 | using grpc::ServerContext; 12 | using grpc::Status; 13 | 14 | using greetings::HelloRequest; 15 | using greetings::HelloReply; 16 | using greetings::Greeter; 17 | 18 | // Logic and data behind the server's behavior. 19 | class GreeterServiceImpl final : public Greeter::Service { 20 | Status SayHello(ServerContext * context, const HelloRequest * request, HelloReply * reply) override { 21 | std::string prefix("Hello "); 22 | reply->set_message(prefix + request->name() + "!"); 23 | return Status::OK; 24 | } 25 | }; 26 | 27 | 28 | void RunServer() { 29 | std::string server_address("0.0.0.0:50051"); 30 | GreeterServiceImpl service; 31 | 32 | ServerBuilder builder; 33 | // Listen on the given address without any authentication mechanism. 34 | builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); 35 | // Register "service" as the instance through which we'll communicate with clients. 36 | // In this case it corresponds to an *synchronous* service. 37 | builder.RegisterService(&service); 38 | // Finally assemble the server. 39 | std::unique_ptr server(builder.BuildAndStart()); 40 | std::cout << "Server listening on " << server_address << std::endl; 41 | 42 | // Wait for the server to shutdown. 43 | // Note that some other thread must be responsible for shutting down the server for this call to ever return. 44 | server->Wait(); 45 | } 46 | 47 | int main(int argc, char ** argv) { 48 | RunServer(); 49 | return 0; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /grpc/arithmetics/arithmetics_server.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include "arithmetics.grpc.pb.h" 8 | 9 | using grpc::Server; 10 | using grpc::ServerBuilder; 11 | using grpc::ServerContext; 12 | using grpc::Status; 13 | 14 | using arithmetics::TwoValueRequest; 15 | using arithmetics::OneValueReply; 16 | using arithmetics::Arithmetics; 17 | 18 | // Logic and data behind the server's behavior. 19 | class ArithmeticsServiceImpl final : public Arithmetics::Service { 20 | Status Add(ServerContext * context, const TwoValueRequest * request, OneValueReply * reply) override { 21 | reply->set_c(request->a() + request->b()); 22 | return Status::OK; 23 | } 24 | Status Minus(ServerContext * context, const TwoValueRequest * request, OneValueReply * reply) override { 25 | reply->set_c(request->a() - request->b()); 26 | return Status::OK; 27 | } 28 | Status Multiply(ServerContext * context, const TwoValueRequest * request, OneValueReply * reply) override { 29 | reply->set_c(request->a() * request->b()); 30 | return Status::OK; 31 | } 32 | Status Divide(ServerContext * context, const TwoValueRequest * request, OneValueReply * reply) override { 33 | reply->set_c(request->a() / request->b()); 34 | return Status::OK; 35 | } 36 | }; 37 | 38 | 39 | void RunServer() { 40 | std::string server_address("0.0.0.0:50051"); 41 | ArithmeticsServiceImpl service; 42 | 43 | ServerBuilder builder; 44 | // Listen on the given address without any authentication mechanism. 45 | builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); 46 | // Register "service" as the instance through which we'll communicate with clients. 47 | // In this case it corresponds to an *synchronous* service. 48 | builder.RegisterService(&service); 49 | // Finally assemble the server. 50 | std::unique_ptr server(builder.BuildAndStart()); 51 | std::cout << "Server listening on " << server_address << std::endl; 52 | 53 | // Wait for the server to shutdown. 54 | // Note that some other thread must be responsible for shutting down the server for this call to ever return. 55 | server->Wait(); 56 | } 57 | 58 | int main(int argc, char ** argv) { 59 | RunServer(); 60 | return 0; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /grpc/greetings/greetings_client.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include "greetings.grpc.pb.h" 8 | 9 | using grpc::Channel; 10 | using grpc::ClientContext; 11 | using grpc::Status; 12 | 13 | using greetings::HelloRequest; 14 | using greetings::HelloReply; 15 | using greetings::Greeter; 16 | 17 | class GreeterClient { 18 | public: 19 | // Constructor 20 | GreeterClient(std::shared_ptr channel): stub_(Greeter::NewStub(channel)) {} 21 | // Assembles the client's payload, sends it and presents the response back from the server. 22 | std::string SayHello(const std::string & user) { 23 | // Data we are sending to the server. 24 | HelloRequest request; 25 | request.set_name(user); 26 | 27 | // Container for the data we expect from the server. 28 | HelloReply reply; 29 | 30 | // Context for the client. 31 | // It could be used to convey extra information to the server and/or tweak certain RPC behaviors. 32 | ClientContext context; 33 | 34 | // The actual RPC. 35 | Status status = stub_->SayHello(&context, request, &reply); 36 | 37 | // Act upon its status. 38 | if (status.ok()) { 39 | return reply.message(); 40 | } 41 | else { 42 | std::cout << status.error_code() << ": " << status.error_message() << std::endl; 43 | return "gRPC failed"; 44 | } 45 | } 46 | 47 | private: 48 | std::unique_ptr stub_; 49 | }; 50 | 51 | void InterativeGRPC() { 52 | // Instantiate the client. It requires a channel, out of which the actual RPCs are created. 53 | // This channel models a connection to an endpoint (in this case, localhost at port 50051). 54 | // We indicate that the channel isn't authenticated (use of InsecureChannelCredentials()). 55 | GreeterClient greeter(grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials())); 56 | while (true) { 57 | std::string user; 58 | std::cout << "Please enter your user name:" << std::endl; 59 | // std::cin >> user; 60 | std::getline(std::cin, user); 61 | std::string reply = greeter.SayHello(user); 62 | if (reply == "gRPC failed") { 63 | std::cout << "gRPC failed" << std::endl; 64 | } 65 | std::cout << "gRPC returned: " << std::endl; 66 | std::cout << reply << std::endl; 67 | } 68 | } 69 | 70 | 71 | int main() { 72 | 73 | InterativeGRPC(); 74 | 75 | return 0; 76 | } 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gRPC Examples 2 | 3 | ## Introduction 4 | 5 | gRPC C++ examples built with CMake. 6 | 7 | ## Dependencies 8 | 9 | * gRPC 1.34 10 | * CMake 3.13.0+ 11 | 12 | ## Files 13 | 14 | ``` 15 | . 16 | ├── CMakeLists.txt 17 | ├── docker 18 | │   └── grpc.Dockerfile 19 | ├── grpc 20 | │   ├── arithmetics 21 | │   │   ├── arithmetics_client.cc 22 | │   │   ├── arithmetics_server.cc 23 | │   │   └── CMakeLists.txt 24 | │   ├── CMakeLists.txt 25 | │   └── greetings 26 | │   ├── CMakeLists.txt 27 | │   ├── greetings_client.cc 28 | │   └── greetings_server.cc 29 | ├── LICENSE.md 30 | ├── protos 31 | │   ├── arithmetics.proto 32 | │   └── greetings.proto 33 | └── README.md 34 | ``` 35 | 36 | ## Usages 37 | 38 | ### Build Docker Image 39 | 40 | ```bash 41 | $ docker build -f docker/grpc.Dockerfile --build-arg GPRC_VERSION=1.34.0 --build-arg NUM_JOBS=8 --tag grpc-cmake:1.34.0 . 42 | ``` 43 | 44 | To build for different gRPC versions and use different number of CPU threads, please change the values in the build arguments. 45 | 46 | 47 | ### Run Docker Container 48 | 49 | Two separate Docker containers should be started for the gRPC server and the gRPC client. 50 | 51 | ```bash 52 | $ docker run -it --rm --network host -v $(pwd):/mnt grpc-cmake:1.34.0 53 | ``` 54 | 55 | ### Build Examples 56 | 57 | ```bash 58 | $ cmake -B build 59 | $ cmake --build build --config Release --parallel 60 | ``` 61 | 62 | All the executable files would be generated in `build/grpc` directory. 63 | 64 | ### Run Examples 65 | 66 | #### Arithmetics 67 | 68 | In one terminal, we start the gRPC server. 69 | 70 | ```bash 71 | $ ./build/grpc/arithmetics/arithmetics_server 72 | Server listening on 0.0.0.0:50051 73 | ``` 74 | 75 | In another terminal, we start the gRPC client. 76 | 77 | ```bash 78 | $ ./build/grpc/arithmetics/arithmetics_client 79 | Please enter your binary arithmetic expression: 80 | 300 + 200 81 | gRPC returned: 82 | 500 83 | Please enter your binary arithmetic expression: 84 | 300 - 200 85 | gRPC returned: 86 | 100 87 | Please enter your binary arithmetic expression: 88 | 300 * 200 89 | gRPC returned: 90 | 60000 91 | Please enter your binary arithmetic expression: 92 | 300 / 200 93 | gRPC returned: 94 | 1 95 | Please enter your binary arithmetic expression: 96 | ``` 97 | 98 | #### Hello World 99 | 100 | In one terminal, we start the gRPC server. 101 | 102 | ```bash 103 | $ ./build/grpc/greetings/greetings_server 104 | Server listening on 0.0.0.0:50051 105 | ``` 106 | 107 | In another terminal, we start the gRPC client. 108 | 109 | ```bash 110 | $ ./build/grpc/greetings/greetings_client 111 | Please enter your user name: 112 | Lei Mao 113 | gRPC returned: 114 | Hello Lei Mao! 115 | Please enter your user name: 116 | Michael Jordan 117 | gRPC returned: 118 | Hello Michael Jordan! 119 | Please enter your user name: 120 | Kobe Bryant 121 | gRPC returned: 122 | Hello Kobe Bryant! 123 | Please enter your user name: 124 | ``` 125 | 126 | ### References 127 | 128 | * [gRPC Tutorial](https://leimao.github.io/blog/gRPC-Tutorial/) 129 | -------------------------------------------------------------------------------- /grpc/arithmetics/arithmetics_client.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "arithmetics.grpc.pb.h" 11 | 12 | using grpc::Channel; 13 | using grpc::ClientContext; 14 | using grpc::Status; 15 | 16 | using arithmetics::TwoValueRequest; 17 | using arithmetics::OneValueReply; 18 | using arithmetics::Arithmetics; 19 | 20 | class ArithmeticsClient { 21 | public: 22 | // Constructor 23 | ArithmeticsClient(std::shared_ptr channel): stub_(Arithmetics::NewStub(channel)) {} 24 | // Assembles the client's payload, sends it and presents the response back from the server. 25 | std::string Compute(int a, int b, char op) { 26 | // Data we are sending to the server. 27 | TwoValueRequest request; 28 | request.set_a(a); 29 | request.set_b(b); 30 | 31 | // Container for the data we expect from the server. 32 | OneValueReply reply; 33 | 34 | // Context for the client. 35 | // It could be used to convey extra information to the server and/or tweak certain RPC behaviors. 36 | ClientContext context; 37 | 38 | // The actual RPC. 39 | Status status; 40 | if (op == '+') { 41 | status = stub_->Add(&context, request, &reply); 42 | } 43 | else if (op == '-') { 44 | status = stub_->Minus(&context, request, &reply); 45 | } 46 | else if (op == '*') { 47 | status = stub_->Multiply(&context, request, &reply); 48 | } 49 | else if (op == '/') { 50 | status = stub_->Divide(&context, request, &reply); 51 | } 52 | else { 53 | std::cout << "Invalid operator!" << std::endl; 54 | } 55 | 56 | // Act upon its status. 57 | if (status.ok()) { 58 | return std::to_string(reply.c()); 59 | } 60 | else { 61 | std::cout << status.error_code() << ": " << status.error_message() << std::endl; 62 | return "RPC failed"; 63 | } 64 | } 65 | 66 | private: 67 | std::unique_ptr stub_; 68 | }; 69 | 70 | void InterativeGRPC() { 71 | // Instantiate the client. It requires a channel, out of which the actual RPCs are created. 72 | // This channel models a connection to an endpoint (in this case, localhost at port 50051). 73 | // We indicate that the channel isn't authenticated (use of InsecureChannelCredentials()). 74 | ArithmeticsClient calculator(grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials())); 75 | while (true) { 76 | std::string expression; 77 | // std::cout << "Please enter your binary arithmetic expression (please do not use space):" << std::endl; 78 | // std::cin >> expression; 79 | std::cout << "Please enter your binary arithmetic expression:" << std::endl; 80 | std::getline(std::cin, expression); 81 | std::vector tokens; 82 | 83 | std::size_t prev = 0, pos; 84 | char op; 85 | while ((pos = expression.find_first_of("+-*/", prev)) != std::string::npos) 86 | { 87 | op = expression[pos]; 88 | if (pos > prev) { 89 | tokens.push_back(expression.substr(prev, pos - prev)); 90 | } 91 | prev = pos + 1; 92 | } 93 | if (prev < expression.length()) 94 | { 95 | tokens.push_back(expression.substr(prev, std::string::npos)); 96 | 97 | } 98 | if (tokens.size() != 2) { 99 | std::cout << "The binary arithmetic expression has to have exactly three tokens!" << std::endl; 100 | continue; 101 | } 102 | 103 | int a = std::stoi(tokens[0]); 104 | int b = std::stoi(tokens[1]); 105 | // std::cout << a << op << b << std::endl; 106 | std::string reply = calculator.Compute(a, b, op); 107 | if (reply == "gRPC failed") { 108 | std::cout << "gRPC failed" << std::endl; 109 | } 110 | std::cout << "gRPC returned: " << std::endl; 111 | std::cout << reply << std::endl; 112 | } 113 | } 114 | 115 | int main() { 116 | 117 | InterativeGRPC(); 118 | 119 | return 0; 120 | } 121 | --------------------------------------------------------------------------------