本例的环境为:WIN10 + VS2015
gRPC 的版本为: 1.4.2
protobuf 的版本为: 3.3.2
下载并安装 Active State Perl。本例下载的是:ActivePerl-5.24.1.2402-MSWin32-x86-64int-401627.exe。安装后打开命令行,输入以下命令验证安装,如果出现版本信息,就说明安装成功了。
> perl -v
This is perl 5, version 24, subversion 1 (v5.24.1) built for MSWin32-x86-multi-thread-64int
(with 1 registered patch, see perl -V for more detail)
...
下载并安装 Go (注意:你可能需要设置代理来下载)。本例下载的是:go1.8.3.windows-amd64.msi。安装后打开命令行,输入以下命令验证安装,如果出现版本信息,就说明安装成功了。
> go version
go version go1.8.3 windows/amd64
打开命令行,新建一个目录专门用来放置 gRPC 的源码,然后进入该目录。本例是在 G 盘下建立的 grpc 目录,大家应该根据实际情况修改。
> cd G:
> md grpc & cd grpc
用 git 下载 gRPC 源码,本例下载的版本是 1.4.2 。
> git clone -b v1.4.2 https://github.com/grpc/grpc.git grpc_v1.4.2
下载后可以在源码根目录找到 INSTALL.md
,里面详细介绍了编译方法。
下载源码后,可以在源码根目录下找到 .gitmodules
文件,该文件是 git 用来描述依赖库的,可以看到 gRPC 的依赖库有:protobuf,gflags,googletest,boringssl,cares,zlib。这些依赖库都需要下载到 third_party
目录下。可以执行以下命令下载这些依赖库,也可以跳过这一步,转到第 5 步开始手动下载。
> git submodule update --init
进入到 third_party
目录,下面开始下载 gRPC 的依赖库。
> cd third_party
下载 protobuf,这里下载的版本是 3.3.2。
> git clone -b v3.3.2 https://github.com/google/protobuf.git protobuf
下载 gflags 。
> git clone https://github.com/gflags/gflags.git gflags
下载 googletest 。
> git clone https://github.com/google/googletest.git googletest
下载 boringssl 。
> git clone https://github.com/google/boringssl.git boringssl
下载 cares 。需要注意下载的版本为:cares-1_12_0
。下载的目录为 cares\cares
。
> git clone -b cares-1_12_0 https://github.com/c-ares/c-ares.git cares/cares
下载 zlib 。
> git clone https://github.com/madler/zlib.git zlib
找到 third_party\boringssl
目录下的 CMakeLists.txt
,用编辑器打开它,搜索 MSVC_DISABLED_WARNINGS_LIST
,找到后,在下面添加 "C4819"
,消除警告:该文件包含不能在当前代码页(数字)中表示的字符。 以 Unicode 格式保存该文件防止数据丢失。
切换到源码目录,在源码目录下创建一个 .build
(如果要编译64位,则是 .build_x64
)子目录,我们用该目录保存所有生成的工程文件。创建后进入该目录。
32位:
> md .build & cd .build
64位:
> md .build_x64 &cd .build_x64
用 cmake 生成工程文件。生成后可以在 .build
(或 .build_x64
)目录下看到生成的工程和项目文件。
32位:
> cmake .. -G "Visual Studio 14 2015" -DCMAKE_BUILD_TYPE=Release
64位:
> cmake .. -G "Visual Studio 14 2015 Win64" -DCMAKE_BUILD_TYPE=Release
使用 MSBuild 编译工程。打开 VS2015 开发人员命令提示符,切换到 .build
(或 .build_x64
)目录下,执行下面的命令进行编译。
编译 32 位 Debug 版本:
> MSBuild ALL_BUILD.vcxproj /t:Build /p:Configuration=Debug;Platform=Win32
编译 32 位 Release 版本:
> MSBuild ALL_BUILD.vcxproj /t:Build /p:Configuration=Release;Platform=Win32
编译 64 位 Debug 版本:
> MSBuild ALL_BUILD.vcxproj /t:Build /p:Configuration=Debug;Platform=x64
编译 64 位 Release 版本:
> MSBuild ALL_BUILD.vcxproj /t:Build /p:Configuration=Release;Platform=x64
如果遇到如下错误,则用编辑器打开 .build\third_party\boringssl\crypto_test_data.cc
,在第 2604 行最后面的双引号 "
之前加个空格。保存,退出,重新编译。
G:\grpc\grpc_v1.4.2\.build\third_party\boringssl\crypto_test_data.cc(2604): error C2001: 常量中有换行符
编译好之后,可以在相应项目目录下的 Debug
和 Release
子目录中找到我们需要的库和工具。如下所示(仅列出重要部分):
.build\
|-Debug\
| |-grpc++.lib -- C++ 的 gRPC 库
| |-grpc_cpp_plugin.exe -- 用来生成 C++ 的 RPC 代码
|-third_party\ -- 这里放的是 gRPC 的依赖库
|-boringssl\
| |-crypto\
| | |-Debug\
| | |-crypto.lib
| |-ssl\
| |-Debug\
| |-ssl.lib
|-cares\
| |-Debug\
| |-cares.lib
|-gflags\
| |-Debug\
| | |-gflags_nothreads_static.lib
|-protobuf\
| |-Debug\
| |-libprotocd.lib -- protocol buffer 库
| |-protoc.exe -- protocol buffer 编译器
|-zlib\
|-Debug\
|-zlibstaticd.lib
下面写一个小程序测试一下。
新建 [空白解决方案],命名为 Calculator。如下图:
添加 [Win32 控制台应用程序],命名为 ICalc。如下图:
在 [应用程序设置页面],勾选 [空项目]。如下图所示。点击完成。
将 .build\third_party\protobuf\Debug\protoc.exe
和 .build\Debug\grpc_cpp_plugin.exe
拷贝到项目目录中。拷贝后的目录如下所示:
新建 [C++ 文件(.cpp)],命名为 calculator.proto
。注意一定要带 .proto
后缀,否则的话后缀就变成 .cpp
了。如下图所示:
calculator.proto
右键,[属性]。 [项类型] 选择 [自定义生成工具]。点击[应用] 按钮。如下图所示:
在 [自定义生成工具] -> [常规] 下,[命令行]填写如下命令:
protoc --cpp_out=. calculator.proto
protoc --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin.exe calculator.proto
[说明] 填写 Performing Protoc Build Tools
。[输出] 填写 None
。[链接对象] 改为 [否]。 如下图所示:
打开 calculator.proto
,编写如下代码:
syntax = "proto3";
package calc;
service Caltulator {
rpc Add(Request) returns (Response) {}
}
message Request {
int32 a = 1;
int32 b = 2;
}
message Response {
int32 sum = 1;
}
编译项目,成功后会在项目目录中生成如下文件:
calculator.pb.h
calculator.pb.cc
calculator.grpc.pb.h
calculator.grpc.pb.cc
其中,calculator.pb.h
和 calculator.pb.cc
是通过 protoc.exe 编译生成的接口数据类型,在这里就是我们在 calculator.proto
中定义的 Request
和 Response
。calculator.grpc.pb.h
和 calculator.grpc.pb.cc
是通过 grpc_cpp_plugin.exe
编译生成的服务器以及存根代码。有了这些文件,就可以开始编写服务器和客户端的代码了。
新建 [Win32 控制台应用程序],命名为 Server
。如下图所示:
在 [应用程序设置] 页面,勾选 [空项目] 。如下图所示:
项目右键,[添加现有项],选择上面生成的那四个接口文件:
项目 [属性] -> [C/C++] -> [常规] -> [附加包含目录],加入 gRPC 和 Protocol Buffer 的头文件,如下图所示。注意这里应该换成自己实际的目录。
项目 [属性] -> [链接器] -> [常规] -> [附加库目录],添加 gRPC 及其依赖库的目录,如下图所示。注意这里应该换成自己实际的目录。
项目 [属性] -> [链接器] -> [输入] -> [附加依赖库],添加 gRPC 及其依赖的库,如下图所示。
工程 [属性] -> [C/C++] -> [预处理器] -> [预处理器定义],添加 _WIN32_WINNT=0x600
。
新建 [C++ 文件(.cpp)],命名为 main.cpp
,代码如下:
#include "../ICalc/calculator.grpc.pb.h"
#include "grpc++/grpc++.h"
class CalcualtorService : public calc::Caltulator::Service
{
// 构造、析构
public:
// 接口实现
public:
virtual ::grpc::Status Add(::grpc::ServerContext* context,
const ::calc::Request* request, ::calc::Response* response) override
{
response->set_sum(request->a() + request->b());
return grpc::Status::OK;
}
};
int main()
{
std::string server_address("0.0.0.0:50051");
CalcualtorService service;
grpc::ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
std::unique_ptr server(builder.BuildAndStart());
std::cout << "Server listening on " << server_address << std::endl;
server->Wait();
return 0;
}
编译工程。生成 Server.exe
。
实现客户端的步骤和实现服务器的一样,只是最后的 main.cpp 不一样而已。这里简单列出步骤。
Client
。calculator.pb.h calculator.pb.cc calculator.grpc.pb.h calculator.grpc.pb.cc
_WIN32_WINNT=0x600
新建 main.cpp,代码如下:
#include
#include "grpc++/grpc++.h"
#include "../ICalc/calculator.grpc.pb.h"
class Client
{
public:
Client(std::shared_ptr channel)
: stub_(calc::Caltulator::NewStub(channel)) {}
google::protobuf::int32 Add(google::protobuf::int32 a, google::protobuf::int32 b)
{
calc::Request request;
request.set_a(a);
request.set_b(b);
calc::Response response;
grpc::ClientContext context;
grpc::Status status = stub_->Add(&context, request, &response);
if (status.ok())
{
return response.sum();
}
else
{
return -1;
}
}
private:
std::unique_ptr stub_;
};
int main()
{
Client client(grpc::CreateChannel(
"localhost:50051", grpc::InsecureChannelCredentials()));
auto result = client.Add(1, 2);
std::cout << "1 + 2 = " << result << std::endl;
return 0;
}
编译工程。生成 Client.exe
。
先启动 Server.exe
,再启动 Client.exe
。结果如下: