在现代软件开发中,gRPC已经成为一个重要的通信框架。作为一个由Google开发并维护的开源项目,gRPC允许不同的服务和应用之间进行有效的远程过程调用(RPC)。它基于HTTP/2协议,不仅提高了通信的效率,还简化了跨语言服务的互操作性。gRPC使用Protocol Buffers作为其接口定义语言,这是一种语言中立的、平台中立的接口描述语言,用于序列化结构化数据。
gRPC的用途广泛,从微服务架构中的服务间通信到支持移动应用和浏览器客户端的后端服务。它的设计使其非常适合于构建分布式系统和云服务,尤其是在需要高效、低延迟通信的场景中。
gRPC之所以在现代应用开发中受到青睐,主要归功于它的几个关键优势。
gRPC适用于多种应用场景,特别是那些需要高效、可靠通信的场景。在微服务架构中,gRPC常被用于服务之间的通信,提供了一种比传统HTTP RESTful API更高效的方法。此外,它也被广泛用于构建API,特别是那些需要支持多种语言客户端的API。
在云计算和分布式系统领域,gRPC的高效性和低延迟特性使其成为组件间通信的理想选择。同时,在物联网(IoT)领域,gRPC因其轻量级和高效性而被用于设备间的通信。
总的来说,gRPC凭借其高性能、跨语言支持和强类型接口,已经成为现代软件开发中不可或缺的一部分。
远程过程调用(RPC)是一种使得在不同计算机环境中运行的程序能够相互调用函数或方法的技术。简而言之,RPC允许一台计算机上的程序调用另一台计算机上的程序,就像调用本地程序一样,而无需关心底层网络技术的细节。RPC抽象了网络通信的复杂性,使开发者能够专注于业务逻辑的实现,而不是通信细节。
Protocol Buffers,简称Protobuf,是由Google开发的一种语言无关、平台无关的序列化框架。它用于序列化结构化数据,类似于XML或JSON,但更小、更快、更简单。在gRPC中,Protobuf用作接口定义语言(IDL),用于定义服务接口和消息格式。
Protobuf的主要优势包括:
gRPC和传统的HTTP/REST服务在多个方面有显著的不同:
参考grpc官网
在开始安装gRPC之前,确保您的系统满足以下要求:
操作系统:Linux(如Ubuntu)、macOS 或 Windows。
编译工具:如gcc、g++(对于Linux/macOS)或 Visual Studio(对于Windows)。
Git:用于克隆gRPC仓库。
Python:如果打算使用Python版本的gRPC。
其他依赖:如autoconf、libtool、pkg-config等。
安装gRPC涉及以下几个主要步骤:
安装依赖项。
克隆gRPC仓库。
编译和安装gRPC。
安装gRPC C++插件。
安装Protocol Buffers编译器。
(可选)安装Python版本的gRPC。
sudo apt install cmake
得到的只有3.10,因此要卸载掉旧版本的cmake,源码编译高版本的。具体方法参考cmake github网站,这里不详述。sudo apt update
sudo apt install build-essential autoconf libtool pkg-config
git clone https://github.com/grpc/grpc
git tag
git checkout v1.45.2
git submodule update --init
MY_INSTALL_DIR=$HOME/.local
echo $MY_INSTALL_DIR
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 $(nproc)
sudo make install
popd
特别说明一下,官网不建议直接安装在/usr/local里,怕不好卸载,所有选择
$HOME/.local
cd third_party/protobuf/
./autogen.sh
./configure --prefix=$HOME/.local # 路径选择之前安装grpc的路径
make
sudo make install
sudo ldconfig # 使得新安装的动态库能被加载
protoc --version
# 显示3.19.4
pip install grpcio
为了生成Python的gRPC代码,还需要安装gRPC的Python插件:
pip install grpcio-tools
完成以上步骤后,应该已经成功在系统上安装了gRPC及其相关工具。
一个基本的gRPC项目通常包括服务定义(Protocol Buffers)、服务端实现和客户端实现。以下是一个C++项目的示例结构:
grpc-example/
│
├── protos/
│ └── my_service.proto
│
├── servers/
│ └── server.cpp
│
└── clients/
└── client.cpp
syntax = "proto3";
package myservice;
// 定义一个简单的消息
message MyRequest {
string name = 1;
}
message MyResponse {
string greeting = 1;
}
// 定义服务
service MyService {
// 定义一个RPC方法
rpc SayHello (MyRequest) returns (MyResponse);
}
export PATH=$HOME/.local/bin/:$PATH
protoc -I protos/ protos/my_service.proto --cpp_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin`
这将在相应的目录中生成C++代码。
我们为了项目的需要,将cc文件改为cpp文件,生成的文件复制到protos目录下
在 servers/ 目录下创建 server.cpp。
实现 .proto 文件中定义的服务接口。例如:
#include
#include "my_service.grpc.pb.h"
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using myservice::MyRequest;
using myservice::MyResponse;
using myservice::MyService;
// 实现服务类
class MyServiceImpl final : public MyService::Service {
Status SayHello(ServerContext* context, const MyRequest* request,
MyResponse* reply) override {
std::string prefix("Hello ");
reply->set_greeting(prefix + request->name());
return Status::OK;
}
};
void RunServer() {
std::string server_address("0.0.0.0:50051");
MyServiceImpl service;
ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
std::unique_ptr<Server> server(builder.BuildAndStart());
std::cout << "Server listening on " << server_address << std::endl;
server->Wait();
}
int main(int argc, char** argv) {
RunServer();
return 0;
}
在 clients/ 目录下创建 client.cpp。
实现代码以调用服务端的RPC方法。例如:
#include
#include "my_service.grpc.pb.h"
using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using myservice::MyRequest;
using myservice::MyResponse;
using myservice::MyService;
class MyClient {
public:
MyClient(std::shared_ptr<Channel> channel)
: stub_(MyService::NewStub(channel)) {}
std::string SayHello(const std::string& user) {
MyRequest request;
request.set_name(user);
MyResponse reply;
ClientContext context;
Status status = stub_->SayHello(&context, request, &reply);
if (status.ok()) {
return reply.greeting();
} else {
std::cout << status.error_code() << ": " << status.error_message()
<< std::endl;
return "RPC failed";
}
}
private:
std::unique_ptr<MyService::Stub> stub_;
};
int main(int argc, char** argv) {
MyClient client(grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials()));
std::string user("World");
std::string reply = client.SayHello(user);
std::cout << "Client received: " << reply << std::endl;
return 0;
}
CXX = g++
CXXFLAGS = -std=c++14 -g -O0 -I/home/ai/.local/include -Iinclude
LDFLAGS = -L/home/ai/.local/lib `pkg-config --libs grpc++ grpc`\
-lgrpc++_reflection\
-lprotobuf -lpthread -ldl
PROTOC = protoc
GRPC_CPP_PLUGIN = grpc_cpp_plugin
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
PROTOS_PATH = protos
OBJS_PATH = objs
vpath %.proto $(PROTOS_PATH)
vpath %.cpp servers:clients:$(PROTOS_PATH)
all: server client
server: $(OBJS_PATH)/my_service.pb.o $(OBJS_PATH)/my_service.grpc.pb.o $(OBJS_PATH)/server.o
$(CXX) $^ $(LDFLAGS) -o $@
client: $(OBJS_PATH)/my_service.pb.o $(OBJS_PATH)/my_service.grpc.pb.o $(OBJS_PATH)/client.o
$(CXX) $^ $(LDFLAGS) -o $@
$(OBJS_PATH)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $< -o $@
clean:
rm -f $(OBJS_PATH)/*.o server client
export LD_LIBRARY_PATH=$HOME/.local/lib:$LD_LIBRARY_PATH
下面就可以正常的编译运行了。
完成以上步骤后,gRPC项目基本结构就搭建好了。可以编译并运行服务端代码,然后编译并运行客户端代码来测试RPC方法的调用。
同时附上CMakeLists.txt的内容,供读者参考。
cmake_minimum_required(VERSION 3.8)
project(YourGrpcProject)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0")
# 包含 gRPC 的头文件
include_directories(/home/ai/mkdi.local/include)
include_directories(include)
# 设置 gRPC 的库路径
link_directories(/home/ai/.local/lib)
# 查找 gRPC 包
find_package(Protobuf REQUIRED) # 要先找Protobuf,否则会报错
find_package(gRPC REQUIRED)
# 如果 gRPC 没有被正确找到,您可能需要设置 gRPC_DIR
# set(gRPC_DIR /path/to/grpc/lib/cmake/grpc)
# 设置源文件
set(SERVER_SOURCE_FILES servers/server.cpp protos/my_service.grpc.pb.cpp protos/my_service.pb.cpp)
set(CLIENT_SOURCE_FILES clients/client.cpp protos/my_service.grpc.pb.cpp protos/my_service.pb.cpp)
# 添加可执行文件
add_executable(server ${SERVER_SOURCE_FILES})
add_executable(client ${CLIENT_SOURCE_FILES})
# 链接 gRPC 和相关库
target_link_libraries(server
gRPC::grpc++ gRPC::grpc++_reflection
protobuf pthread dl z)
target_link_libraries(client
gRPC::grpc++ gRPC::grpc++_reflection
protobuf pthread dl z)
# 如果需要从 .proto 文件生成 .cpp 和 .h 文件,可以使用以下命令,这块暂时没试过,仅供参考。
# find_program(PROTOC_EXECUTABLE protoc)
# find_program(GRPC_CPP_PLUGIN_EXECUTABLE grpc_cpp_plugin)
# add_custom_command(
# OUTPUT "${PROTOS_PATH}/my_service.grpc.pb.cc"
# "${PROTOS_PATH}/my_service.pb.cc"
# COMMAND ${PROTOC_EXECUTABLE}
# ARGS --grpc_out="${PROTOS_PATH}"
# --cpp_out="${PROTOS_PATH}"
# --plugin=protoc-gen-grpc="${GRPC_CPP_PLUGIN_EXECUTABLE}"
# -I "${PROTOS_PATH}"
# "${PROTOS_PATH}/my_service.proto"
# DEPENDS "${PROTOS_PATH}/my_service.proto")
同上一节c++项目
同上一节c++项目
使用 protoc 编译器生成服务代码。根据您使用的编程语言,命令会有所不同。例如,对于Python:
python -m grpc_tools.protoc -I protos/ protos/my_service.proto --python_out=. --grpc_python_out=.
这将在相应的目录中生成Python代码。
创建服务端代码文件server.py。
from concurrent import futures
import grpc
import my_service_pb2
import my_service_pb2_grpc
class MyServiceServicer(my_service_pb2_grpc.MyServiceServicer):
def SayHello(self, request, context):
response = my_service_pb2.MyResponse()
response.greeting = 'Hello, ' + request.name
return response
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
my_service_pb2_grpc.add_MyServiceServicer_to_server(MyServiceServicer(), server)
server.add_insecure_port('[::]:50051')
server.start()
server.wait_for_termination()
if __name__ == '__main__':
serve()
在 client/ 目录下创建客户端代码文件。
实现代码以调用服务端的RPC方法。例如,使用Python:
import grpc
import my_service_pb2
import my_service_pb2_grpc
def run():
with grpc.insecure_channel('localhost:50051') as channel:
stub = my_service_pb2_grpc.MyServiceStub(channel)
response = stub.SayHello(my_service_pb2.MyRequest(name='World'))
print("Client received: " + response.greeting)
if __name__ == '__main__':
run()
完成以上步骤后,python gRPC项目基本结构就搭建好了。可以运行服务端代码,然后运行客户端代码来测试RPC方法的调用。
在本系列文章中,我们深入探讨了 gRPC 的基本概念、安装步骤以及如何在 C++ 和 Python 项目中实际应用 gRPC。从 gRPC 的基础出发,我们首先介绍了其与传统通信框架的比较,突出了 gRPC 在现代应用程序中提供的高效和可靠的 RPC 解决方案。
我们详细讨论了 gRPC 的安装过程,包括在不同操作系统上的安装指南和潜在的挑战。这为读者提供了一个坚实的基础,以便在自己的开发环境中顺利部署 gRPC。
接着,文章重点介绍了如何在 C++ 和 Python 项目中使用 gRPC。通过具体的项目案例,我们展示了在这两种语言中编写、编译和运行 gRPC 服务端和客户端的步骤。这些案例不仅提供了实际的代码示例,还讲解了如何在项目中有效地应用 gRPC,从而使读者能够更好地理解和运用这一技术。
总体而言,本系列文章旨在提供一个全面的 gRPC 学习指南,从基本概念到实际应用,特别是在 C++ 和 Python 项目中的应用。通过这些内容,读者可以获得必要的知识和技能,以在自己的项目中有效地利用 gRPC,实现高效和可靠的服务间通信。