C++ grpc简单实例解析,源码分析

proto 文件

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

// 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;
}

编译 proto 文件

protoc --cpp_out=. helloworld.proto
protoc --grpc_out=. --plugin=protoc-gen-grpc=/usr/local/bin/grpc_cpp_plugin helloworld.proto

获得四个文件
在这里插入图片描述

服务端代码

#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::HelloRequest;
using helloworld::HelloReply;
using helloworld::Greeter;

// Logic and data behind the server's behavior.
class GreeterServiceImpl final : public Greeter::Service {
  Status SayHello(ServerContext* context, const HelloRequest* request,
                  HelloReply* reply) override {
    std::string prefix("wanjun 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;
}

编译指令

g++ -std=c++11 *.cc -o server -pthread -lprotobuf -lgrpc++

编译成功后便可执行

详细解析

class GreeterServiceImpl final : public Greeter::Service 

我们的Greeter服务器自动生成了一个嵌套类Service,用于继承并实现我们的虚函数。
在server.cc文件中,我们构造了Service的子类对象GreeterServiceImpl用于实现我们特定的方法。

Greeter::Service 源码

  class Service : public ::grpc::Service {
   public:
    Service();
    virtual ~Service();
    // Sends a greeting
    virtual ::grpc::Status SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response);
  };

由此可见只有一个虚函数SayHello
该虚函数在 .cc 文件中的实现为

::grpc::Status Greeter::Service::SayHello(::grpc::ServerContext* context, const ::helloworld::HelloRequest* request, ::helloworld::HelloReply* response) {
  (void) context;
  (void) request;
  (void) response;
  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}

并没有任何任何实现,只是给虚函数提供了一个基类方法。
SayHello 方法的参数如下
grpc::ServerContext context 上下文
helloworld::HelloRequest
request 传入的参数(请求)
helloworld::HelloReply* response 传出的结果(回复)
在 .proto 文件中我们已经定义了 HelloRequest & HelloReply 两个Message

  Status SayHello(ServerContext* context, const HelloRequest* request,
                  HelloReply* reply) override {
    std::string prefix("wanjun Hello ");
    reply->set_message(prefix + request->name());
    return Status::OK;
  }

override 表示覆盖基类中的虚函数,在实现中为获取了每个request的 name field ,并且添加了一个前缀作为reply返回。

RunServer() 函数

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();
}

ServerBuilder 作为最重要的一个类
/// A builder class for the creation and startup of \a grpc::Server instances.
一个builder用于创建和开启一个grpc服务器实例

ServerBuilder& AddListeningPort(const grpc::string& addr_uri,
                                  std::shared_ptr<ServerCredentials> creds,
                                  int* selected_port = nullptr);

为一个grpc::Server绑定一个端口。

ServerBuilder& RegisterService(Service* service);

注册一个服务,函数调用并不会获得service的所有权。

virtual std::unique_ptr<Server> BuildAndStart();

返回一个运行的服务器,已经准备好了去处理函数调用。
智能指针 std::unique_ptr 会自动清理内存。

Server

  /// Block until the server shuts down.
  /// \warning The server must be either shutting down or some other thread must
  /// call \a Shutdown for this function to ever return.
  void Wait() override;

阻塞等待服务器关闭

Client 客户端

#include <string>
#include <iostream>
#include <memory>
#include <grpcpp/grpcpp.h>
#include "helloworld.grpc.pb.h"
using grpc::ClientContext;
using grpc::Channel;
using grpc::Status;
using helloworld::HelloReply;
using helloworld::HelloRequest;
using helloworld::Greeter;

// static method : Greeter::NewStub
class wjClient{
public:
    wjClient(std::shared_ptr<Channel> channel)
        :stub_(Greeter::NewStub(channel)){
    }

    std::string SayHello(std::string name){
        ClientContext context;
        HelloReply reply;
        HelloRequest request;
        request.set_name(name);

        Status status = stub_->SayHello(&context,request,&reply);

        if(status.ok()){
            return reply.message();
        }else{
            return "failure";
        }
    }

private:
    std::unique_ptr<Greeter::Stub> stub_;
};

int main(int argc,char *argv[]){
    auto channel = grpc::CreateChannel("0.0.0.0:5001",grpc::InsecureChannelCredentials());
    wjClient client(channel);
    // block until get result from RPC server
    std::string result = client.SayHello("wanjun");
    printf("get result [%s]\n",result.c_str());
    return 0;
}

解析
在Greeter 类中 StubInterface 类实现了提供给 Client 客户端使用的接口

class Stub final : public StubInterface

表示 Stub 继承自 StubInterface 并且不可被再继承,在我们的客户端代码中当做 wjClient 的私有变量 stub_ 使用。
stub_ 的赋值使用 Greeter::NewStub() 类静态方法获取,后续调用 SayHello() 完成对 RPC server 远程服务器的调用。

Channel 通道

每个 Client 都需要 Channel 来实现对远程服务器的调用,使用 grpc::CreateChannel() 函数来创建一个通信管道。

猜你喜欢

转载自blog.csdn.net/weixin_40021744/article/details/86749788