gRPC系列文章 gRPC++ HelloWorld项目

我看很多人一上来就把gRPC自带的ssl库给替换成openssl,实际上对于ssl没有特别的需求大可不必去把gRPC默认的ssl替换。


开发环境

  • Windows 7
  • Visual studio 2015
  • gRPC 1.27.0

实例项目仓库


gRPC四类服务方法

gRPC 允许你定义四类服务方法:

单项 RPC,即客户端发送一个请求给服务端,从服务端获取一个应答,就像一次普通的函数调用。

rpc SayHello(HelloRequest) returns (HelloResponse){
}

服务端流式 RPC,即客户端发送一个请求给服务端,可获取一个数据流用来读取一系列消息。客户端从返回的数据流里一直读取直到没有更多消息为止。

rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse){
}

客户端流式 RPC,即客户端用提供的一个数据流写入并发送一系列消息给服务端。一旦客户端完成消息写入,就等待服务端读取这些消息并返回应答。

rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse) {
}

双向流式 RPC,即两边都可以分别通过一个读写数据流来发送一系列消息。这两个数据流操作是相互独立的,所以客户端和服务端能按其希望的任意顺序读写,例如:服务端可以在写应答前等待所有的客户端消息,或者它可以先读一个消息再写一个消息,或者是读写相结合的其他方式。每个数据流里消息的顺序会被保持。

rpc BidiHello(stream HelloRequest) returns (stream HelloResponse){
}

HelloWorld-gRPC项目仓库

新建解决方案

用vs2015新建一个解决方案:两个c++控制台项目
在这里插入图片描述

HelloWorld Server端项目

准备proto文件helloworld.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;
}

大家可以选择在vs安装一个编辑proto文件的插件,方便以后编辑proto。
在这里插入图片描述

生成proto的源文件

grpc.pb源文件

PS C:\Program Files (x86)\grpc\bin> .\protoc.exe --grpc_out="C:\Users\stand\Documents\Visual Studio 2015\Projects\gRPC-E
xamples\gRPC-Example-HelloWorldServer" --plugin="protoc-gen-grpc=grpc_cpp_plugin.exe" --proto_path="C:\Users\stand\Docum
ents\Visual Studio 2015\Projects\gRPC-Examples\gRPC-Example-HelloWorldServer" helloworld.proto
  • grpc_out:编译目标文件输出目录
  • plugin:指定语言的plugin
  • proto_path:proto文件查找目录
  • 最后指定要编译的proto文件名

pb文件

PS C:\Program Files (x86)\grpc\bin> .\protoc.exe --cpp_out="C:\Users\stand\Documents\Visual Studio 2015\Projects\gRPC-E
xamples\gRPC-Example-HelloWorldServer" --plugin="protoc-gen-grpc=grpc_cpp_plugin.exe" --proto_path="C:\Users\stand\Docum
ents\Visual Studio 2015\Projects\gRPC-Examples\gRPC-Example-HelloWorldServer" helloworld.proto

运行以上两条命令之后会生成四个源文件:
在这里插入图片描述
源文件里的内容就是helloworld - rpc 的stub。

将这四个文件添加进项目中。
在这里插入图片描述

添加C++头文件包含目录

在这里插入图片描述

添加依赖的静态库

需要手动添加静态库,不然会出现“无法解析的符号”从而导致编译失败。
在这里插入图片描述

C:\Program Files (x86)\grpc\lib\libprotobufd.lib;
C:\Program Files (x86)\grpc\lib\grpc.lib;
C:\Program Files (x86)\grpc\lib\gpr.lib;
C:\Program Files (x86)\grpc\lib\upb.lib;
C:\Program Files (x86)\grpc\lib\grpc++.lib;
C:\Program Files (x86)\grpc\lib\address_sorting.lib;
C:\Program Files (x86)\grpc\lib\cares.lib;
C:\Program Files (x86)\grpc\lib\ssl.lib;
C:\Program Files (x86)\grpc\lib\zlibstaticd.lib;
C:\Program Files (x86)\grpc\lib\crypto.lib;
C:\Program Files (x86)\grpc\lib\absl_base.lib;
C:\Program Files (x86)\grpc\lib\absl_bad_optional_access.lib;
C:\Program Files (x86)\grpc\lib\absl_dynamic_annotations.lib;
C:\Program Files (x86)\grpc\lib\absl_int128.lib;
C:\Program Files (x86)\grpc\lib\absl_strings.lib;
C:\Program Files (x86)\grpc\lib\absl_strings_internal.lib;
C:\Program Files (x86)\grpc\lib\absl_throw_delegate.lib

码代码

Windows项目不要忘记了向源文件中添加“#include “stdafx.h””

HelloWorld Server端mian源文件

#include "stdafx.h"
#include "helloworld.pb.h"
#include "helloworld.grpc.pb.h"
#include "grpcpp\grpcpp.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("Hello ");
		std::string postfix(" power by C++");
		reply->set_message(prefix + request->name()+postfix);
		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();
}

#include <iostream>

using namespace std;

int main(int argc, char** argv) {

	cout << "ready go to sleeping" << endl;
	RunServer();

	return 0;
}


HelloWorld Client端项目

Client端需要和Server一样的引入头文件和静态库文件。

HelloWorld Client端main源文件

#include "stdafx.h"

#include <iostream>
#include <memory>
#include <string>

//#include <grpcpp/grpcpp.h>
#include "grpcpp\grpcpp.h"


#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "helloworld.grpc.pb.h"
#endif

using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;
using helloworld::HelloRequest;
using helloworld::HelloReply;
using helloworld::Greeter;

class GreeterClient {
public:
	GreeterClient(std::shared_ptr<Channel> channel)
		: stub_(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.
		HelloRequest request;
		request.set_name(user);

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

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

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

		// Act upon its status.
		if (status.ok()) {
			return reply.message();
		}
		else {
			std::cout << status.error_code() << ": " << status.error_message()
				<< std::endl;
			return "RPC failed";
		}
	}

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

int main(int argc, char** argv) {
	// 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);
	std::cout << "Greeter received: " << reply << std::endl;
	
	std::cin.get();
	return 0;
}

测试

生成解决方案

在debug目录运行程序
在这里插入图片描述
在这里插入图片描述
ok


gRPC系列文章

gRPC系列文章 RPC概念、数据传输协议、序列化协议

gRPC系列文章 gRPC++项目生成、编译

gRPC系列文章 gRPC++ HelloWorld项目

gRPC系列文章 SpringBoot下的HelloWorld

发布了54 篇原创文章 · 获赞 9 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/wangxudongx/article/details/104234673