gRPC简介及简单使用(C++)

gRPC是一个现代的、开源的、高性能远程过程调用(RPC)框架,可以在任何平台运行。gRPC使客户端和服务器端应用程序能够透明地进行通信,并简化了连接系统的构建。gRPC支持的语言包括C++、Ruby、Python、Java、Go等。

gRPC默认使用Google的Protocol Buffers,关于Protocol Buffers的介绍可以参考:https://blog.csdn.net/fengbingchun/article/details/49977903

gRPC的源码在https://github.com/grpc/grpc,最新版本的版本为v1.23.0,它的license是Apache-2.0。

关于RPC(Remote Procedure Call, 远程过程调用)的介绍可以参考:https://blog.csdn.net/fengbingchun/article/details/92406377

关于gRPC的安装可以参考:https://blog.csdn.net/fengbingchun/article/details/100608370

下面参考gRPC官方examples/cpp/helloworld中的同步模式例子,过程如下:

1. 创建IDL(interface definition language)描述文件helloworld.proto,通过protobuf定义服务端与客户端之间的RPC调用接口,通过protoc工具生成客户端和服务端代码。gRPC是需要先定义服务接口约定,才可以进行RPC调用,使用.proto可以同时定义客户端和服务端交换的数据格式以及RPC调用的接口。helloworld.proto文件内容如下:

// Copyright 2015 gRPC authors.

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

通过protoc工具生成服务端和客户端代码,执行命令(终端定位在demo/gRGC_Test)如下:

./../../src/grpc/linux_install/bin/protoc --cpp_out=./ helloworld.proto
./../../src/grpc/linux_install/bin/protoc --grpc_out=./ --plugin=protoc-gen-grpc=./../../src/grpc/linux_install/bin/grpc_cpp_plugin helloworld.proto

会在当前目录下生成helloworld.pb.h, hellowrold.pb.cc, helloworld.grpc.pb.h, helloworld.grpc.pb.cc四个文件。使用IDL定义服务端方法、参数、返回类型,客户端和服务端都使用从服务端定义生成的接口代码。

2. 编写客户端代码,测试代码函数为test_grpc_client;

3. 编写服务端代码,测试代码函数为test_grpc_server;

#include "funset.hpp"
#include <iostream>
#include <memory>
#include <string>
#include <grpcpp/grpcpp.h>
#include "helloworld.grpc.pb.h"

// reference: grpc/examples/cpp/helloworld
namespace {

class GreeterClient {
public:
	GreeterClient(std::shared_ptr<grpc::Channel> channel) : stub_(helloworld::Greeter::NewStub(channel)) {}

	// Assembles the client's payload, sends it and presents the response back from the server.
  	std::string SayHello(const std::string& user) {
    		// Data we are sending to the server.
    		helloworld::HelloRequest request;
    		request.set_name(user);

    		// Container for the data we expect from the server.
    		helloworld::HelloReply reply;

    		// Context for the client. It could be used to convey extra information to the server and/or tweak certain RPC behaviors.
    		grpc::ClientContext context;

    		// The actual RPC.
    		grpc::Status status = stub_->SayHello(&context, request, &reply);

    		// Act upon its status.
    		if (status.ok()) {
      			return reply.message();
    		} else {
      			fprintf(stderr, "error code: %d, error message: %s\n", status.error_code(), status.error_message().c_str());
      			return "RPC failed";
   		}	
  	}	

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

} // namespace

int test_grpc_client()
{
	fprintf(stdout, "client start\n");
  	// Instantiate the client. It requires a channel, out of which the actual RPCs are created.
	// This channel models a connection to an endpoint (in this case, localhost at port 50051).
	// We indicate that the channel isn't authenticated(use of InsecureChannelCredentials()).
  	GreeterClient greeter(grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials()));
  	std::string user("world");
  	std::string reply = greeter.SayHello(user);
  	fprintf(stdout, "Greeter received: %s\n", reply.c_str());

	return 0;
}

namespace {

// Logic and data behind the server's behavior.
class GreeterServiceImpl final : public helloworld::Greeter::Service {
  	grpc::Status SayHello(grpc::ServerContext* context, const helloworld::HelloRequest* request, helloworld::HelloReply* reply) override {
    		std::string prefix("Hello ");
    		reply->set_message(prefix + request->name());
    		return grpc::Status::OK;
  	}
};

void RunServer() {
  	std::string server_address("0.0.0.0:50051");
  	GreeterServiceImpl service;

  	grpc::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<grpc::Server> server(builder.BuildAndStart());
  	fprintf(stdout, "Server listening on: %s\n", server_address.c_str());

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

} // namespace

int test_grpc_server()
{
	fprintf(stdout, "server start\n");
	RunServer();

	return 0;
}

4. 先在一个终端启动服务端程序,再在另一个终端启动客户端程序,执行结果如下:

GitHubhttps://github.com/fengbingchun/OpenSSL_Test

发布了718 篇原创文章 · 获赞 1131 · 访问量 609万+

猜你喜欢

转载自blog.csdn.net/fengbingchun/article/details/100626030