总结由于gRPC主要由Google开发,由于一些已知的原因,gRPC的demo还是不太顺利。单独写这篇文章,主要是gRPC安装过程中坑太多,记录一下,免得大家走弯路。主要坑:如果使用PHP或者Python开发gRPC客户端,需要编译gRPC命令行工具生成proto代码生成插件,否则无法编译proto中定义的服务。编译需要使用GCC4.8以上版本,否则报不支持C++11。然后下周需要加速grpc源码,下载大量的第三方依赖。这个过程非常痛苦。使用golang和java的可以忽略。PHP也需要遵循grpc的c扩展。编译需要使用GCC4.8或更高版本。如果使用golang开发服务,依赖的第三方服务基本下载不了。github仓库需要使用gomod添加映射规则,github下载速度慢。本文在讲解gRPCdemo的同时说明了如何解决这些陷阱。本文对应的Github地址:https://github.com/52fhy/grpc...。仓库存放demo示例和一些系统编译好的二进制包。每个人都认为有些步骤花费的时间太长。可以直接clone仓库,把二进制包复制到对应目录下(只做测试开发,生产环境还是老老实实自己编译吧)。升级GCCgRPC命令行工具编译,需要使用GCC4.8及以上版本。CentOS6系列内置版本为GCC4.7。使用gcc--version查看版本。如果您的系统GCC版本>=4.8,您可以忽略此部分。如果你只使用golang、java,请忽略此部分。注意:不建议大家下载GCC源码包或者使用yum下载GCC4.8及以上版本。原因:1)安装源码包真的非常非常慢2)yum源码的下载速度慢得像蜗牛。下面的SCL安装方法推荐给大家使用,安装后还是可以使用原版的。如果需要将gcc升级到4.8或更高版本,建议安装SCL源后直接安装devtoolset-6(devtoolset-6当前gcc版本为6.3),因为devtoolset-4及之前的版本已经结束支持和只能通过其他方式安装。升级到gcc6.3:yum-yinstallcentos-release-sclyum-yinstalldevtoolset-6-gccdevtoolset-6-gcc-c++devtoolset-6-binutilssclenabledevtoolset-6bash需要注意的是scl命令的启用只是暂时的。退出shell或重启都会恢复原来的系统gcc版本。如果想长期使用gcc6.3:echo"source/opt/rh/devtoolset-6/enable">>/etc/profile,然后退出shell,重新打开就可以看到新版本的gcc了。这同样适用于其他版本。升级到gcc7.3:yum-yinstallcentos-release-sclyum-yinstalldevtoolset-7-gccdevtoolset-7-gcc-c++devtoolset-7-binutilssclenabledevtoolset-7bash已经停止支持devtoolset4(gcc5.2)及之前的了版本的安装方法可能比较慢,有兴趣的可以试试。升级到gcc4.8:wgethttp://people.centos.org/tru/devtools-2/devtools-2.repo-O/etc/yum.repos.d/devtoolset-2.repoyum-yinstalldevtoolset-2-gccdevtoolset-2-gcc-c++devtoolset-2-binutilsscl启用devtoolset-2bash升级到gcc4.9:wgethttps://copr.fedoraproject.org/coprs/rhscl/devtoolset-3/repo/epel-6/rhscl-devtoolset-3-epel-6.repo-O/etc/yum.repos.d/devtoolset-3.repoyum-yinstalldevtoolset-3-gccdevtoolset-3-gcc-c++devtoolset-3-binutilsscl启用devtoolset-3bash升级到gcc5.2:wgethttps://copr.fedoraproject.org/coprs/hhorak/devtoolset-4-rebuild-bootstrap/repo/epel-6/hhorak-devtoolset-4-rebuild-bootstrap-epel-6.repo-O/etc/yum.repos.d/devtoolset-4.repoyuminstalldevtoolset-4-gccdevtoolset-4-gcc-c++devtoolset-4-binutils-ysclenabledevtoolset-4bashcompilegRPCcommandlinetools如果只使用golang,java,请忽略此部分。gRPC分为C、JAVA、GO、NodeJS版本。C版本包括C++、Python、Ruby、Objective-C、PHP和C#。这些语言都是基于C版本开发的,共享一个代码库。C版:https://github.com/grpc/grpcJAVA版:https://github.com/grpc/grpc-...GO版:https://github.com/grpc/grpc-goNode版:https://github.com/grpc/grpc-...如果你使用的是C版本的gRPC,你最终会从源码中编译出以下工具:对于原型编译器。你需要先在grpc/grpcgithub上下载源码。gitclone-b$(curl-Lhttps://grpc.io/release)https://github.com/grpc/grpccdgrpcgitsubmoduleupdate--initmake&&sudomakeinstall#生成的插件路径ll./bins/opt/#复制到bin目录cp-r./bins/opt/*/usr/local/bin/这里有2个坑:1.grpc/grpc仓库比较大。鉴于国内访问速度,建议使用国内镜像。码云(https://gitee.com)提供了一个同步更新的镜像地址:gitclonehttps://gitee.com/mirrors/grpc-frameworkgrpc这样下载速度提升不少。2.gitsubmoduleupdate命令实际上是将.gitmodules文件中定义的第三方依赖下载到third_party目录下。有很多依赖关系。您可以打开.gitmodules文件查看详细信息。依赖的仓库都在github上,下载几个小时都下载不下来,只能等下载慢了。回过头来看,我们花了很多时间,才搞定grpc的proto编译插件。好处:Mac下编译好的二进制包:https://files.cnblogs.com/fil...。下载并解压以上文件,将bins/opt/下的所有文件复制到/usr/local/bin/下。如果您只使用golang和java进行PHP相关支持,请忽略本节。PHP目前不支持充当grpc服务器。作为客户端,可以并且需要在机器上安装:protoc编译工具protobufcextensiongRPC命令行工具(grpc_php_plugin)grpccextensiongrpcphplibrary其中protoc和protobufcextension已经在Protobufsmall中介绍过了测试,这里就不赘述了。如果上一节安装成功,那么grpc_php_plugin也是可用的。下面介绍如何安装PHP版的gRPC库。安装grpcc扩展:要求:GCC编译器需要4.8及以上版本。可以使用pecl安装:peclinstallgrpc也可以指定版本:peclinstallgrpc-1.12.0或者下载源码(http://pecl.php.net/package/grpc)安装:wgethttp:///pecl.php.net/get/grpc-1.21.3.tgztarzxvfgrpc-1.21.3.tgz&&cdgrpc-1.21.3phpize./configuremakemakeinstallgrpc/grpc代码库还有PHP扩展的C源码,在grpc/src/php/ext/grpc目录也可以直接编译。编译后在php.ini中添加,使用php--rigrpc查看信息。安装C扩展后,还需要使用composer安装grpc库:composerrequiregrpc/grpcgRPCExampleWritinggRPCproto定义了三个文件:└──proto├──GreeterService.proto├──Response.proto└──在User.proto中,User定义为Model,Response用于RPC统一返回定义,GreeterService定义为服务接口。限于篇幅,proto文件详见https://github.com/52fhy/grpc...仓库的proto目录。GreeterService.proto文件内容如下:syntax="proto3";packageSample.Model;//namesapceimport"User.proto";import"Response.proto";serviceGreeter{//发送一个问候rpcSayHello(User)returns(Response){}}这里定义了一个服务,相当于定义了一个服务接口。我们定义了方法名和参数,后面需要实现。由于gRPC不支持PHP作为服务端,这里我们使用Golang作为服务端。首先需要使用proto工具编译golang代码:mkdir-pPb_Go#Compilecdprotoprotoc--go_out=plugins=grpc:../Pb_Go/*.protocd-如果提示protoc-gen-go找不到,请参考文章介绍(https://www.cnblogs.com/52fhy...)进行安装。如果执行成功,会在Pb_Go目录下生成Go代码:Pb_Go├──GreeterService.pb.go├──Response.pb.go└──User.pb.go如果需要生成PHP客户端代码,你需要使用grpcphp命令行工具grpc_php_plugin,如果前面的总结执行成功,说明这个工具已经存在了。然后:out=output/phpmkdir-p$out#Compilecdprotoprotoc--php_out=../$out--grpc_out=../$out--plugin=protoc-gen-grpc=/usr/local/bin/grpc_php_plugin*.protocd-#修改命名空间cd$outmvGPBMetadataSample/Model/find.-名称'*.php'!-nameexample.php-execsed-i""-e's#GPBMetadata#Sample\\Model\\GPBMetadata#g??'-e's#\\Sample\\Model\\GPBMetadata\\Google#\\GPBMetadata\\谷歌#g'{}\;以上是在Mac下操作,命令与Linux有些区别。gRPC编译工具在CentOS下没有编译。最终生成的文件:├──output│└──php│└──Sample│└──Model│├──GPBMetadata││├──GreeterService.php││├──Response.php││└──User.php│├──GreeterClient.php│├──Response.php│├──User.php│└──UserList.php注意:如果不加--grpc_out=../$out--plugin=protoc-gen-grpc=/usr/local/bin/grpc_php_plugin,生成的PHP类没有GreeterClient。该文件由gRPC编译工具自动生成,用于连接gRPC服务器。Go编写服务我们使用Golang来编写服务端。上面虽然生成了部分Golang代码,但是真正的服务还没有写出来。main.go首先,让我们创建一个新的main.go。代码不多,直接贴出来:golang.org/grpc")const(addr=":50051")//server用来实现helloworld.GreeterServer.typeserverstruct{}//SayHello实现helloworld.GreeterServerfunc(s*server)SayHello(ctxcontext.Context,u*pb.User)(*pb.Response,error){return&pb.Response{ErrCode:0,ErrMsg:"success",Data:map[string]string{"name":"Hello"+u.Name}},nil}funcmain(){lis,err:=net.Listen("tcp",addr)iferr!=nil{log.Fatalf("failedtolisten:%v",err)}fmt.Printf("%sserverstartat%s\n",time.Now(),addr)s:=grpc.NewServer()pb.RegisterGreeterServer(s,&server{})s.Serve(lis)}然后它可以被编译。有个大坑:gobuildmain.go时,会先下载go.mod中定义的依赖(依赖有很多,详见:https://github.com/52fhy/grpc...),下面的非常慢,repo太大了,虽然重定向到github:替换google.golang.org/api=>github.com/googleapis/google-api-go-clientv0.6.1-0.20190616000641-99157d28da34快速下载,我在码云上做了一个镜像,地址:gitee.com/52fhy/google-api-go-client。更改后,下载速度更快。编译成功后生成二进制文件main。我们可以直接运行:$./main2019-06-3017:16:07.752508+0800CSTm=+0.028838467serverstartat:50051gotest为了测试我们写的服务是否正常,我们可以写一个测试用例:test_client.gopackagemainimport("context""google.golang.org/grpc"pb"grpc-sample/Pb_Go""testing")funcTestExec(t*testing.T){conn,err:=grpc.Dial(":50051",grpc.WithInsecure())iferr!=nil{t.Errorf("dialerror:%v\n",err)}deferconn.Close()//实例化客户端client:=pb.NewGreeterClient(conn)//调用服务user:=pb.User{}user.Id=1user.Name="test"result,err:=client.SayHello(context.Background(),&user)iferr!=nil{t.Errorf("grpcerror:%v\n",err)}t.Logf("Recevied:%v\n",result)}运行:$gotest-vclient_test.go===RUNTestExec---PASS:TestExec(0.01s)client_test.go:29:Recevied:errMsg:"success"data:
