引言
关于gRPC随着云原生微服务的火热也流行了起来,而且学好一个gRPC框架对目前来说也是必须的了。然而对于一个基础的小白来说,这个gRPC的框架运用起来是及其的困难,具体体现在依赖库繁多,且大部分需要对git进行代理,在实际运用框架时,常常会发现某些库或者头文件找不到了,常常是些编译链接错误,还是很烦的。本篇文章通过博主自己整理的非常简单的操作来让新手小白进行一个友好的入门,并且对于博主自己也是一个笔记的作用,并且对于一些用到的第三方库也给出了百度网盘的链接,跟着步骤来还是很容易上手的,也没什么废话,跟着教程实操起来吧!
一、快速安装
1. 安装必要依赖库
执行以下命令安装
sudo apt update
sudo apt-get update
sudo apt install -y protobuf-compiler libprotobuf-dev # 安装protobuf编译器和库
sudo apt install -y build-essential autoconf libtool pkg-config libsystemd-dev libssl-dev # 安装依赖项
sudo apt install -y libgflags-dev libgtest-dev libc++-dev clang cmake # 安装c++支持
sudo apt-get install autoconf automake libtool # 依赖工具
2. 安装gRPC
tar -jxf grpc-v1.45.2.tar.bz2
cd grpc-v1.45.2
mkdir -p cmake/build
cd cmake/build
cmake ../..
make -j 4
sudo make install # 安装到系统目录
二、测试使用
先运行以下命令创建测试文件,然后将文件中的内容填充到对应的文件里
mkdir gRPC-test
cd gRPC-test
touch client.cc CMakeLists.txt helloworld.proto server.cc
helloworld.proto
syntax = "proto3";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloResponse) {}
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string message = 1;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(helloworld)
set(CMAKE_CXX_STANDARD 17)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR})
# 查找 Protobuf 库
find_package(Protobuf CONFIG REQUIRED)
find_package(gRPC CONFIG REQUIRED)
# 添加 server 可执行程序
add_executable(server
server.cc helloworld.grpc.pb.cc helloworld.pb.cc
)
# 添加对 protobuf 和 gRPC 库的链接
target_link_libraries(server PRIVATE
gRPC::grpc++ # CMake 提供的目标库名称
gRPC::grpc++_reflection # CMake 提供的目标库名称
protobuf::libprotobuf # CMake 提供的目标库名称
)
# 添加 client 可执行程序
add_executable(client
client.cc helloworld.grpc.pb.cc helloworld.pb.cc
)
# 添加对 protobuf 和 gRPC 库的链接
target_link_libraries(client PRIVATE
gRPC::grpc++
gRPC::grpc++_reflection
protobuf::libprotobuf
)
server.cc
#include <iostream>
#include <memory>
#include <string>
#include <grpcpp/grpcpp.h>
#include "helloworld.grpc.pb.h"
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using helloworld::Greeter;
using helloworld::HelloRequest;
using helloworld::HelloResponse;
// Logic and data behind the server's behavior.
class GreeterServiceImpl final : public Greeter::Service {
Status SayHello(ServerContext* context, const HelloRequest* request,
HelloResponse* reply) override {
std::string prefix("Hello ");
reply->set_message(prefix + request->name());
return Status::OK;
}
};
void RunServer() {
std::string server_address("0.0.0.0:50051");
GreeterServiceImpl service;
ServerBuilder builder;
// Listen on the given address without any authentication mechanism.
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
// Register "service" as the instance through which we'll communicate with
// clients. In this case it corresponds to an *synchronous* service.
builder.RegisterService(&service);
// Finally assemble the server.
std::unique_ptr<Server> server(builder.BuildAndStart());
std::cout << "Server listening on " << server_address << std::endl;
// Wait for the server to shutdown. Note that some other thread must be
// responsible for shutting down the server for this call to ever return.
server->Wait();
}
int main(int argc, char** argv) {
RunServer();
return 0;
}
client.cc
#include <iostream>
#include <memory>
#include <string>
#include <grpcpp/grpcpp.h>
#include "helloworld.grpc.pb.h"
using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using helloworld::Greeter;
using helloworld::HelloRequest;
using helloworld::HelloResponse;
class GreeterClient {
public:
GreeterClient(std::shared_ptr<Channel> channel)
: stub_(Greeter::NewStub(channel)) {}
// Assembles the client's payload, sends it and presents the response back
// from the server.
std::string SayHello(const std::string& user) {
// Data we are sending to the server.
HelloRequest request;
request.set_name(user);
// Container for the data we expect from the server.
HelloResponse reply;
// Context for the client. It could be used to convey extra information to
// the server and/or tweak certain RPC behaviors.
ClientContext context;
// The actual RPC.
Status status = stub_->SayHello(&context, request, &reply);
// Act upon its status.
if (status.ok()) {
return reply.message();
} else {
std::cout << status.error_code() << ": " << status.error_message()
<< std::endl;
return "RPC failed";
}
}
private:
std::unique_ptr<Greeter::Stub> stub_;
};
int main(int argc, char** argv) {
// Instantiate the client. It requires a channel, out of which the actual RPCs
// are created. This channel models a connection to an endpoint specified by
// the argument "--target=" which is the only expected argument.
// We indicate that the channel isn't authenticated (use of
// InsecureChannelCredentials()).
std::string target_str;
std::string arg_str("--target");
if (argc > 1) {
std::string arg_val = argv[1];
size_t start_pos = arg_val.find(arg_str);
if (start_pos != std::string::npos) {
start_pos += arg_str.size();
if (arg_val[start_pos] == '=') {
target_str = arg_val.substr(start_pos + 1);
} else {
std::cout << "The only correct argument syntax is --target=" << std::endl;
return 0;
}
} else {
std::cout << "The only acceptable argument is --target=" << std::endl;
return 0;
}
} else {
target_str = "localhost:50051";
}
GreeterClient greeter(grpc::CreateChannel(
target_str, grpc::InsecureChannelCredentials()));
std::string user("world");
std::string reply = greeter.SayHello(user);
std::cout << "Greeter received: " << reply << std::endl;
return 0;
}
执行以下命令进行编译生成可执行程序
protoc -I=. --grpc_out=./ --cpp_out=./ --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` ./helloworld.proto # 生成.pb.h .pb.cc .grpc.pb.h .grpc.pb.cc
mkdir build
cd build
cmake .. # 生成Makefile文件
make # 编译
然后打开两个终端运行程序,出现如下图说明已经测试成功啦
./server # 第一个shell
./client # 第二个shell