gRPC
RPC
RPC(Remote Procedure Call Protocol)–远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息的到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。
简介
gRPC 一开始由 google 开发,是一款语言中立、平台中立、开源的远程过程调用(RPC)系统。
gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持。
gRPC 默认使用 protocol buffers,这是 Google 开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如 JSON)。
编译
$ git clone https://github.com/grpc/grpc.git
$ cd grpc
$ git submodule update --init
$ make
$ sudo make install
TestCase
下面以c++为测试语言
proto定义
// Login.proto
syntax="proto3";
package rs;
message Response{
int32 code = 1;
string errmsg = 2;
}
message LoginRequest{
string username = 1;
string password = 2;
}
message LoginResponse{
int32 id = 1;
string username = 2;
string token = 3;
}
message LogoutRequest{
int32 id = 1;
string username = 2;
string token = 3;
}
service LoginService{
rpc Login(LoginRequest) returns (LoginResponse) {}
rpc Logout(LogoutRequest) returns (Response) {}
}
$ protoc -Iproto --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` rs/Login.proto --grpc_out=cpp
$ protoc -Iproto rs/Login.proto --cpp_out=cpp
服务端代码
#include <grpcpp/grpcpp.h>
#include "rs/Login.grpc.pb.h"
using namespace rs;
using grpc::Server;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using rs::Response;
using rs::LoginRequest;
using rs::LoginResponse;
using rs::LogoutRequest;
class LoginServiceImpl : public LoginService::Service{
public:
LoginServiceImpl() {}
~LoginServiceImpl() {}
virtual ::grpc::Status Login(ServerContext* context, const LoginRequest* request, LoginResponse* response){
response->set_id(1);
response->set_username(request->username());
response->set_token("ABCDEFGHIJKLMNOPQRSTUVWXYZ123456");
return Status::OK;
}
virtual ::grpc::Status Logout(ServerContext* context, const LogoutRequest* request, Response* response){
response->set_code(200);
response->set_errmsg("OK");
return Status::OK;
}
};
void RunServer() {
std::string server_address("0.0.0.0:12345");
LoginServiceImpl 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;
}
$ g++ -g -Wall -std=c++11 server.cpp rs/Login.grpc.pb.cc rs/Login.pb.cc -I. -o server -lprotobuf -lgrpc++
客户端代码
#include <grpcpp/grpcpp.h>
#include "rs/Login.grpc.pb.h"
using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using namespace rs;
int main(int argc, char* argv[]){
std::string srvaddr = "127.0.0.1:12345";
std::shared_ptr<Channel> channel = grpc::CreateChannel(srvaddr, grpc::InsecureChannelCredentials());
std::unique_ptr<LoginService::Stub> stub = LoginService::NewStub(channel);
ClientContext ctx;
LoginRequest req;
req.set_username("hw");
req.set_password("admin123");
LoginResponse res;
Status status = stub->Login(&ctx, req, &res);
if (status.ok()){
req.PrintDebugString();
res.PrintDebugString();
}else{
printf("{errcode:%d,errmsg:%s,detail:%s}", status.error_code(),
status.error_message().c_str(), status.error_details().c_str());
}
LogoutRequest reqLogout;
reqLogout.set_id(res.id());
reqLogout.set_username(res.username());
reqLogout.set_token(res.token());
Response resLogout;
ClientContext ctx2;
status = stub->Logout(&ctx2, reqLogout, &resLogout);
if (status.ok()){
resLogout.PrintDebugString();
}else{
printf("{errcode:%d,errmsg:%s,detail:%s}", status.error_code(),
status.error_message().c_str(), status.error_details().c_str());
}
return 0;
}
$ g++ -g -Wall -std=c++11 client.cpp rs/Login.grpc.pb.cc rs/Login.pb.cc -I. -o client -lprotobuf -lgrpc++
参考资料
gRPC官方文档:https://grpc.io/docs/
gPRC中文文档:http://doc.oschina.net/grpc