赞
踩
一、前言
这两天想研究一下grpc的Protobuf,于是在自己的mac电脑上进行尝试。把过程记录下来,给有需要的同学参考下,大家共同进步。
参考grpc官网:https://grpc.io
二、下载grpc代码包
使用dep包管理工具直接下载grpc代码包,命令为:
dep ensure -add google.golang.org/grpc
下载完成后,在Gopkg.toml文件里会新增以下内容:
- [[constraint]]
- name = "google.golang.org/grpc"
- version = "1.20.1"
三、安装protoc工具
安装protoc编译器,以生成grpc服务代码。
3.1 下载protoc源代码
下载protoc编译器源码地址为:https://github.com/protocolbuffers/protobuf/releases
笔者下载版本为protobuf-all-3.7.1.tar.gz
3.2 编译所需的依赖工具
编译protoc源代码需要的依赖工具为:autoconf、automake、libtool、curl、make、g++、unzip。
3.21.查看autoconf是否已安装,如果没有,使用brew安装:
$ brew install autoconf
3.2.2查看automake是否已安装,如果没有,使用brew安装:
$ brew install automake
3.2.3查看libtool是否已安装,如果没有,使用brew安装:
$ brew install libtool
3.2.4 查看curl是否已安装,如果没有,使用brew安装:
$ brew install curl
3.2.5 查看make是否已安装,如果没有,使用brew安装:
$ brew install make
3.2.6查看g++是否已安装,如果没有,使用brew安装:
$ brew install g++
3.2.7查看unzip是否已安装,如果没有,使用brew安装:
$ brew install unzip
3.3执行配置脚本
解压缩protobuf-all-3.7.1.tar.gz,进入解压后的目录,执行配置脚本:
- $ cd ~/Downloads/protobuf-3.7.1
- $ ./autogen.sh
3.4 编译与安装
- $ ./configure --prefix=/usr/local/protobuf
- $ make
- $ make check
- $ make install
3.5 设置环境变量
编辑.bash_profile配置文件,设置环境变量,重新加载配置文件:
- $ vi ~/.bash_profile
- #### protoc
- export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/protobuf/lib
- export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/protobuf/lib
- export PATH=$PATH:/usr/local/protobuf/bin
-
- $ source ~/.bash_profile
3.6 检查protoc编译工具是否安装成功
- $ protoc --version
- libprotoc 3.7.1
四、安装protoc-gen-go插件工具
安装protoc-gen-go插件工具,以支持生成go语言版本的服务代码。
4.1 下载protoc-gen-go插件工具的源代码包(注意:GOPATH路径为~/Go)
$ go get -u github.com/golang/protobuf/protoc-gen-go
4.2 安装生成protoc-gen-go插件工具
- $ cd ~/Go/src/github.com/golang/protobuf/protoc-gen-go
- $ go install
安装完成后,就会发现:在GOPATH/bin目录下,已生成protoc-gen-go文件。
五、示例
5.1 protobuf示例
该示例源自gRPC-go的examples的helloworld,代码路径为:
vendor/google.golang.org/grpc/examples/helloworld/helloworld/helloworld.proto
先看下pb文件的内容:
- syntax = "proto3";
-
- option java_multiple_files = true;
- option java_package = "io.grpc.examples.helloworld";
- option java_outer_classname = "HelloWorldProto";
-
- 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;
- }

该文件定义了一个服务Greeter,其中定义了一个API SayHello
。该API接受参数为HelloRequest
类型,返回值为HelloReply
类型,这里HelloRequest
和HelloReply都是
普通的PB定义。
使用protoc命令生成相关文件,命令为:
- $ cd grpc/examples/helloworld
- $ protoc -I helloworld/ helloworld.proto --go_out=plugins=grpc:helloworld
可以看到,在helloworld.proto同级目录下会生成对应的pb.go文件helloworld.pb.go。注意:在命令行中使用了plugins选项,提供对grpc的支持,否则不会生成Service的接口。
5.2 服务端程序
服务端程序示例如下:
- package main
-
- import (
- "log"
- "net"
-
- pb "your_path_to_gen_pb_dir/helloworld"
- "golang.org/x/net/context"
- "google.golang.org/grpc"
- )
-
- const (
- port = ":50051"
- )
-
- // server is used to implement helloworld.GreeterServer.
- type server struct{}
-
- // SayHello implements helloworld.GreeterServer
- func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
- return &pb.HelloReply{Message: "Hello " + in.Name}, nil
- }
-
- func main() {
- lis, err := net.Listen("tcp", port)
- if err != nil {
- log.Fatalf("failed to listen: %v", err)
- }
- s := grpc.NewServer()
- pb.RegisterGreeterServer(s, &server{})
- s.Serve(lis)
- }

可以看到,首先定义一个server结构,实现SayHello的接口,该接口定义在“your_path_to_gen_pb_dir/helloworld.proto”中。
然后,在main方法中调用grpc.NewServer()
方法创建一个server s。
接着,调用 pb.RegisterGreeterServer(s, &server{})方法将自定义的
server注册到这个server s中。
最后,将创建的net.Listener传给s.Serve()
。
这样,就可以开始监听,并提供服务了,类似HTTP的ListenAndServe。
5.3 客户端程序
客户端程序示例如下:
- package main
-
- import (
- "log"
- "os"
-
- pb "your_path_to_gen_pb_dir/helloworld"
- "golang.org/x/net/context"
- "google.golang.org/grpc"
- )
-
- const (
- address = "localhost:50051"
- defaultName = "world"
- )
-
- func main() {
- // Set up a connection to the server.
- conn, err := grpc.Dial(address, grpc.WithInsecure())
- if err != nil {
- log.Fatalf("did not connect: %v", err)
- }
- defer conn.Close()
- c := pb.NewGreeterClient(conn)
-
- // Contact the server and print out its response.
- name := defaultName
- if len(os.Args) > 1 {
- name = os.Args[1]
- }
- r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})
- if err != nil {
- log.Fatalf("could not greet: %v", err)
- }
- log.Printf("Greeting: %s", r.Message)
- }

可以看到,首先调用grpc.Dial方法产生一个grpc的ClientConn;然后,以这个ClientConn为参数,调用pb.NewGreeterClient()创建一个client;最后,通过这个client,直接调用对应服务器端的接口。
注意:在编译执行helloworld/greeter_server和helloworld/greeter_client时,如果提示proto.ProtoPackageIsVersion3不存在,那么修改下Gopkg.toml文件中关于grpc的部分:
- [[constraint]]
- name = "google.golang.org/grpc"
- branch = "master"
然后,用dep包管理工具重新加载下,就ok了。命令为:
$ dep ensure -update
原因为dep ensure默认加载的是proto2版本,但示例中使用的时proto3版本,升级下代码包版本就可以了。
六、结束语
初次接触grpc和protobuf,要学的还有很多。本文仅把mac下学习安装protoc工具和protoc-gen-go插件工具的过程记录下来,提供给有需要的同学参考下。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。