简单使用gRPC

gRPC是google开发的一个远程过程调用框架,搭配protobuf使用来实现从客户端调用服务器端对应程序的方法。

protobuf#

protobuf可以理解为一种传输协议或者传输格式,相比json等网络传输形式,具有更好的效率。gRPC使用这种协议来实现高效的网络传输。

proto#

只需要编写proto文件,再使用gRPC提供的工具,就可以直接生成多种语言的客户端和服务端,以及对应的protobuf协议,因此还可以实现跨语言的程序调用。简单的proto文件格式如下:

# service.proto

syntax = "proto3";

package message;

service HelloWorld {
	rpc sayHello (Request) returns (Response) {}
}

message Request {
	string name = 1;
}

message Response {
	int32 error = 1;
	string code = 2;
}

syntax关键字指定了protobuf的版本,默认版本是proto2,一般指定使用proto3。
package关键字将会生成一个命名空间,用于隔离代码,下面生成的服务和请求格式都会放到message这个命名空间下。
service关键字指明了我们要生成的客户端和服务端的名称,然后内部通过rpc关键字表示将会调用到的函数,这里我们创建的客户端和服务端的RPC服务就叫HelloWorld,里面有一个会被远程调用的函数叫sayHello,入参是一个Request类型,出参是Response类型,这两个类型在下面通过message关键字来定义。

生成客户端和服务端#

当客户端HelloWorld调用sayHello时,会通过网络将Request传递到同名的服务端HelloWorld中,然后HelloWorld调用同名的sayHello函数,将执行结果返回。

服务端#

在生成好proto文件后,我们要在自己的代码中实例化我们定义的gRPC服务。
查看生成好的源文件能够看到,在对应的类内部会有一个HelloWorld::Service的类,我们需要继承这个类,然后来实现对应的逻辑。

// 服务的具体实现
class HelloWorldServiceImpl final : public HelloWorld::Service {
  Status SayHello(ServerContext* context, const Request* request, Response* 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");
  HelloWorldServiceImpl 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();
}

首先是设置监听地址和端口,然后通过gRPC中提供的ServerBuilder构建类来构建出一个服务,最后使用服务的Wait函数,服务将进入阻塞等待接收消息。

客户端#

同样,我们也可以定义一个自己的客户端类,并在这个类中包含gRPC客户端对应的“存根”,gRPC客户端主要就是通过这个存根来和服务器端进行通信的。

class HelloWorldClient {
 public:
  HelloWorldClient(std::shared_ptr<Channel> channel)
      : stub_(HelloWorld::NewStub(channel)) {}

  std::string sayHello(const std::string& user) {
    Request request;
    request.set_name(user);
    Response reply;
    ClientContext context;
    Status status = stub_->sayHello(&context, request, &reply);
    if (status.ok()) {
      return reply.code();
    } else {
      std::cout << status.error_code() << ": " << status.error_message() << std::endl;
      return "RPC failed";
    }
  }

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

关键部分在于HelloWorld::Stub,Channel和ClientContext,HelloWorld::Stub就是我们说的存根,这个是在生成的gRPC源文件中自动生成的,这个类的实现需要一个通道Channel,Channel中可以设置要通信的服务端的地址和端口号。

std::shared_ptr<Channel> channel = grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials());

在远程调用sayHello时,还需要传入一个叫做客户端上下文的东西,也就是ClientContext,还有表示接口调用状态的Status,都可以在grcpp中找到,引入对应的头文件即可。

作者:cwtxx

出处:https://www.cnblogs.com/cwtxx/p/18718199

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   cwtxx  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示