Quick start
This guide gets you started with gRPC in C++ with a simple working example.
Quick start
In the C++ world, there’s no universally accepted standard for managing project dependencies. You need to build and install gRPC before building and running this quick start’s Hello World example.
Build and locally install gRPC and Protocol Buffers
The steps in the section explain how to build and locally install gRPC and
Protocol Buffers using cmake
. If you’d rather use bazel, see Building
from source.
Setup
Choose a directory to hold locally installed packages. This page assumes that
the environment variable MY_INSTALL_DIR
holds this directory path. For
example:
$ export MY_INSTALL_DIR=$HOME/.local
Ensure that the directory exists:
$ mkdir -p $MY_INSTALL_DIR
Add the local bin
folder to your path variable, for example:
$ export PATH="$MY_INSTALL_DIR/bin:$PATH"
Install cmake
You need version 3.13 or later of cmake
. Install it by
following these instructions:
Linux
$ sudo apt install -y cmake
macOS:
$ brew install cmake
For general
cmake
installation instructions, see Installing CMake.
Check the version of cmake
:
$ cmake --version
cmake version 3.19.6
Under Linux, the version of the system-wide cmake
can often be too old. You
can install a more recent version into your local installation directory as
follows:
$ wget -q -O cmake-linux.sh https://github.com/Kitware/CMake/releases/download/v3.19.6/cmake-3.19.6-Linux-x86_64.sh
$ sh cmake-linux.sh -- --skip-license --prefix=$MY_INSTALL_DIR
$ rm cmake-linux.sh
Install other required tools
Install the basic tools required to build gRPC:
Linux
$ sudo apt install -y build-essential autoconf libtool pkg-config
macOS:
$ brew install autoconf automake libtool pkg-config
Clone the grpc
repo
Clone the grpc
repo and its submodules:
$ git clone --recurse-submodules -b v1.35.0 https://github.com/grpc/grpc
Build and install gRPC, Protocol Buffers, and Abseil
While not mandatory, gRPC applications usually leverage Protocol Buffers for service definitions and data serialization, and the example code uses proto3.
gRPC uses the Abseil C++ library, so it needs to be installed as well.
The following commands build and locally install gRPC, Protocol Buffers, and Abseil:
$ cd grpc
$ mkdir -p cmake/build
$ pushd cmake/build
$ cmake -DgRPC_INSTALL=ON \
-DgRPC_BUILD_TESTS=OFF \
-DCMAKE_INSTALL_PREFIX=$MY_INSTALL_DIR \
../..
$ make -j
$ make install
$ popd
$ mkdir -p third_party/abseil-cpp/cmake/build
$ pushd third_party/abseil-cpp/cmake/build
$ cmake -DCMAKE_INSTALL_PREFIX=$MY_INSTALL_DIR \
-DCMAKE_POSITION_INDEPENDENT_CODE=TRUE \
../..
$ make -j
$ make install
$ popd
Important
We strongly encourage you to install gRPC locally — using an appropriately setCMAKE_INSTALL_PREFIX
— because there is no easy way
to uninstall gRPC after you’ve installed it globally.More information:
- You can find a complete set of instructions for building gRPC C++ in Building from source.
- For general instructions on how to add gRPC as a dependency to your C++ project, see Start using gRPC C++.
Build the example
The example code is part of the grpc
repo source, which you cloned as part of
the steps of the previous section.
Change to the example’s directory:
$ cd examples/cpp/helloworld
Build the example using
cmake
:$ mkdir -p cmake/build $ pushd cmake/build $ cmake -DCMAKE_PREFIX_PATH=$MY_INSTALL_DIR ../.. $ make -j
Note
Getting build failures? Most issues, at this point, are a result of a faulty installation. Ensure that the have the right versions ofcmake
, and carefully recheck your installation.
Try it!
Run the example from the example build directory
examples/cpp/helloworld/cmake/build
:
Run the server:
$ ./greeter_server
From a different terminal, run the client and see the client output:
$ ./greeter_client Greeter received: Hello world
Congratulations! You’ve just run a client-server application with gRPC.
Update the gRPC service
Now let’s look at how to update the application with an extra method on the
server for the client to call. Our gRPC service is defined using protocol
buffers; you can find out lots more about how to define a service in a .proto
file in Introduction to gRPC and Basics
tutorial. For now all you need to know is that both the
server and the client stub have a SayHello()
RPC method that takes a
HelloRequest
parameter from the client and returns a HelloResponse
from the
server, and that this method is defined like this:
// 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;
}
Open examples/protos/helloworld.proto and add a new SayHelloAgain()
method, with the
same request and response types:
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
// Sends another greeting
rpc SayHelloAgain (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;
}
Remember to save the file!
Regenerate gRPC code
Before you can use the new service method, you need to recompile the updated proto file.
From the example build directory examples/cpp/helloworld/cmake/build
, run:
$ make -j
This regenerates helloworld.pb.{h,cc}
and helloworld.grpc.pb.{h,cc}
, which
contains the generated client and server classes, as well as classes for
populating, serializing, and retrieving our request and response types.
Update and run the application
You have new generated server and client code, but you still need to implement and call the new method in the human-written parts of our example application.
Update the server
Open greeter_server.cc
from the example’s root directory. Implement the new
method like this:
class GreeterServiceImpl final : public Greeter::Service {
Status SayHello(ServerContext* context, const HelloRequest* request,
HelloReply* reply) override {
// ...
}
Status SayHelloAgain(ServerContext* context, const HelloRequest* request,
HelloReply* reply) override {
std::string prefix("Hello again ");
reply->set_message(prefix + request->name());
return Status::OK;
}
};
Update the client
A new SayHelloAgain()
method is now available in the stub. We’ll follow the
same pattern as for the already present SayHello()
and add a new
SayHelloAgain()
method to GreeterClient
:
class GreeterClient {
public:
// ...
std::string SayHello(const std::string& user) {
// ...
}
std::string SayHelloAgain(const std::string& user) {
// Follows the same pattern as SayHello.
HelloRequest request;
request.set_name(user);
HelloReply reply;
ClientContext context;
// Here we can use the stub's newly available method we just added.
Status status = stub_->SayHelloAgain(&context, request, &reply);
if (status.ok()) {
return reply.message();
} else {
std::cout << status.error_code() << ": " << status.error_message()
<< std::endl;
return "RPC failed";
}
}
Finally, invoke this new method in main()
:
int main(int argc, char** argv) {
// ...
std::string reply = greeter.SayHello(user);
std::cout << "Greeter received: " << reply << std::endl;
reply = greeter.SayHelloAgain(user);
std::cout << "Greeter received: " << reply << std::endl;
return 0;
}
Run!
Run the client and server like you did before. Execute the following commands
from the example build directory examples/cpp/helloworld/cmake/build
:
Build the client and server after having made changes:
$ make -j
Run the server:
$ ./greeter_server
On a different terminal, run the client:
$ ./greeter_client
You’ll see the following output:
Greeter received: Hello world Greeter received: Hello again world
Note
Interested in an asynchronous version of the client and server? You’ll find thegreeter_async_{client,server}.cc
files in the
example’s source directory.What’s next
- Learn how gRPC works in Introduction to gRPC and Core concepts.
- Work through the Basics tutorial.
- Explore the API reference.