gRPC

gRPC

RPC

RPC(Remote Procedure Call Protocol)–远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。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支持语言

gRPC调用模型

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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ithewei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值