首先需要编译gRPC ,编译参考  原文 http://blog.csdn.net/cupidove/article/details/53334920

获取gRPC源码

gRPC是开源框架,项目代码在github上,所以首先要安装github。
github安装后,在指定文件夹中,执行git命令就可以获取gRPC的所有源码。
git clone  https://github.com/grpc/grpc.git
cd grpc
git submodule update --init     获取third_party的源代码

step1. 编译protobuf

参考readme用CMAKE生成工程文件,编译即可。首先打开vs2015开发人员命令提示符窗口,切换到对应的protobuf目录

具体步骤:

1:cd protobuf

2: Git clone -b release-1.7.0 https://github.com/google/googlemock.git gmock

3:cd gmock

4:git clone -b release-1.7.0 https://github.com/google/googletest.git gtest

5:cd ..\cmake

6:mkdir build & cd build & mkdir install

7:mkdir debug & cd debug

8:cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=../install ../..

9:nmake && nmake install

10:生成完成,在install目录下面有对应的Lib文件。在cmake目录下面mkdir debug,然后把install/lib目录下的所有库文件拷贝的debug路径,并把后缀d去掉。例如protobuf生成的库名称为libprotocd.lib,应该改名成libprotoc.lib。其他的依次类推。后面编译grpc会用到这些库。


方法二、可以直接在cmake目录用cmakelists.txt  直接生产工程文件编译


step2. 编译grpc,grpc_protoc_plugin在vsprojects里有建好的工程文件,下载nuget.exe,用于依赖包的网络下载。主要是依赖于openssl和zlib库。在编译grpc时,出现编译boringssl,出现很多错误,可以把工程移除

具体步骤:

1:cd vsprojects

2:nuget restore grpc.sln

3:msbuild grpc.sln /p:Configuration=Debug

grpc库生成成功。

4:编译grpc_cpp_plugin,执行命令:msbuild grpc_protoc_plugins.sln /p:Configuration=Debug

grpc_cpp_plugin.exe插件编译成功


用vs2015编译基本不会遇到什么问题,除了: grpc_cpp_plugin依赖libprotoc.lib,而protobuf生成的库名称为libprotocd.lib,这块需要手动改一下


定义如下格式的 asyncservice.proto文件,内容如下
syntax = "proto3";

package cecily;

service School {
  rpc HelloStudent(Student) returns (Teacher) {}
  rpc HelloTeacher(Teacher) returns (Student) {}
}

message Student {
  bytes name = 1;
  int32 age = 2;  
  int32 number = 3;
}

message Teacher {
  bytes name = 1;
  int32 age = 2;
  bytes school = 3;
}

定义了两个rpc 服务, HelloStudent(入参Student 返回值 Teacher) 和 HelloTeacher(入参Teacher 返回值 Student), 然后使用 protoc.exe 和 grpc_cpp_plugin.exe生成 asyncservice.pb.h、 asyncservice.pb.cc 、asyncservice.grpc.pb.h 、asyncservice.grpc.pb.cc 使用命令如下,这样就生成了描述类
protoc.exe -I=.\ --grpc_out=.\ --plugin=protoc-gen-grpc=.\grpc_cpp_plugin.exe  .\asyncservice.proto 
protoc.exe -I=.\ --cpp_out=.\  .\asyncservice.proto 

多线程异步服务端代码如下:
// AsyncServer_Demo.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <memory>
#include <iostream>
#include <string>
#include <thread>
#include <process.h>
#include <grpc++/grpc++.h>
#include <grpc/support/log.h>

#include "asyncservice.grpc.pb.h"


using grpc::Server;
using grpc::ServerAsyncResponseWriter;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::ServerCompletionQueue;
using grpc::Status;
using cecily::Student;
using cecily::Teacher;
using cecily::School;




class ServerImpl final{
public:
	~ServerImpl() {
		server_->Shutdown();   //停止服务
		cq_->Shutdown();
	}

	void Run() {
		std::string server_address("0.0.0.0:66666");
		ServerBuilder builder;
		builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
		builder.RegisterService(&service_);
		cq_ = builder.AddCompletionQueue();
		server_ = builder.BuildAndStart();
		std::cout << "Server listening on " << server_address << std::endl;
		//注册服务 通过CallData对象的状态,在初始状态下,将对应类型的CallData对象传递进入ServerCompletionQueue  的 cq_对象中
		//当有服务请求过来的时候 调用next 能得到对应的请求, 请求类型通过CallData对象的s_type_值区分,用来区分不同的服务,做不同的处理
		new CallData(&service_, cq_.get(), ServerImpl::CallData::SS_HelloStudent);
		new CallData(&service_, cq_.get(), ServerImpl::CallData::SS_HelloTeacher);
		//注册服务  应该有多少个服务有要注册多少个服务, 例子只有两个服务
		//开启多线程处理rpc调用请求
		for ( int i = 0 ; i < 8; i++ )
		{
			_beginthreadex(NULL,
				0,
				ServerImpl::ThreadHandlerRPC,
				(void*)this,
				0,
				0);
		}
		
	}

private:
	class CallData {
	public:
		enum ServiceType {
			SS_HelloStudent = 0,
			SS_HelloTeacher
		};
	public:
		CallData(School::AsyncService* service, ServerCompletionQueue* cq, ServiceType s_type)
		:service_(service),cq_(cq),s_type_(s_type), student_response(&ctx_), teacher_response(&ctx_), status_(CREATE){
			Process();
		}

		void Process() {
			if ( status_ == CREATE )
			{
				status_ = PROCESS;
				switch (s_type_)
				{
					//根据不同的服务 注册不同的 服务类型到 ServerCompletionQueue 队列, 看名字和使用有点像完成端口  (没有去验证研究)
				case ServerImpl::CallData::SS_HelloStudent:
					service_->RequestHelloStudent(&ctx_, &student_request, &student_response, cq_, cq_, this);
					break;
				case ServerImpl::CallData::SS_HelloTeacher:
					service_->RequestHelloTeacher(&ctx_, &teacher_request, &teacher_response, cq_, cq_, this);
					break;
				default:
					break;
				}
			}
			else if (status_ == PROCESS) {
				status_ = FINISH;
				new CallData(service_, cq_, this->s_type_);
				switch (s_type_)
				{
				case ServerImpl::CallData::SS_HelloStudent: {
					std::string name = student_request.name();
					int age = student_request.age();
					std::string prefix("Cecily HelloStudent: ");
					int nThreadID = GetCurrentThreadId();
					char szTmp[20] = { 0 };
					sprintf_s(szTmp,20, "线程:%d", nThreadID);
					std::string end(szTmp);
					teacher_request.set_name(prefix + name + end);
					status_ = FINISH;
					
					student_response.Finish(teacher_request, Status::OK, this);
				}
					break;
				case ServerImpl::CallData::SS_HelloTeacher: {
					std::string schoolname = teacher_request.school();
					std::string prefix("Cecily HelloTeacher: ");
					int nThreadID = GetCurrentThreadId();
					char szTmp[20] = { 0 };
					sprintf_s(szTmp, 20, "线程:%d", nThreadID);
					std::string end(szTmp);
					student_request.set_name(prefix + schoolname +end);
					status_ = FINISH;
					teacher_response.Finish(student_request, Status::OK, this);
				}
					break;
				default:
					break;
				}
			}
			else {
				GPR_ASSERT(status_ == FINISH);
				delete this;
			}
			
		}

	

	private:
		School::AsyncService* service_;
		ServerCompletionQueue* cq_;
		ServerContext ctx_;
		ServiceType s_type_;
		Student student_request;
		::grpc::ServerAsyncResponseWriter< ::cecily::Teacher> student_response;
		Teacher teacher_request;
		::grpc::ServerAsyncResponseWriter< ::cecily::Student> teacher_response;

		enum CallStatus { CREATE, PROCESS, FINISH };
		CallStatus status_; 
	};

private:

	static unsigned __stdcall ThreadHandlerRPC(void* lparam) {
		ServerImpl* impl = (ServerImpl*)lparam;
		impl->HandleRPCS();
		return 1;
	}
	void HandleRPCS() {
		void* tag; 
		bool ok;
		while (true) {
			GPR_ASSERT(cq_->Next(&tag, &ok));//从ServerCompletionQueue 队列拿到获取请求任务,根据请求任务处理 逻辑
			GPR_ASSERT(ok);
			static_cast<CallData*>(tag)->Process();
		}
	}


private:
	std::shared_ptr<ServerCompletionQueue> cq_;
	School::AsyncService service_;
	std::shared_ptr<Server> server_;

};


int main()
{
	ServerImpl server;
	server.Run();
	char c;
	std::cin >> c;
	system("pause");
    return 0;
}

以上内容属于学习记录随笔,因为从接触到写这个博客只有两天时间,中间难免会有不正确的地方,后续发现再更改。





Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐